sdio+fatfs创建
This commit is contained in:
commit
f762d5d7f8
2473 files changed
+1192014
No files matched your search
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __AT91SAM7S_H__
|
||||
#define __AT91SAM7S_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AT91_REG *(volatile unsigned int *) /* Hardware register definition */
|
||||
|
||||
/* ========== Register definition for TC0 peripheral ========== */
|
||||
#define AT91C_TC0_SR (AT91_REG(0xFFFA0020)) /* TC0 Status Register */
|
||||
#define AT91C_TC0_RC (AT91_REG(0xFFFA001C)) /* TC0 Register C */
|
||||
#define AT91C_TC0_RB (AT91_REG(0xFFFA0018)) /* TC0 Register B */
|
||||
#define AT91C_TC0_CCR (AT91_REG(0xFFFA0000)) /* TC0 Channel Control Register */
|
||||
#define AT91C_TC0_CMR (AT91_REG(0xFFFA0004)) /* TC0 Channel Mode Register (Capture Mode / Waveform Mode) */
|
||||
#define AT91C_TC0_IER (AT91_REG(0xFFFA0024)) /* TC0 Interrupt Enable Register */
|
||||
#define AT91C_TC0_RA (AT91_REG(0xFFFA0014)) /* TC0 Register A */
|
||||
#define AT91C_TC0_IDR (AT91_REG(0xFFFA0028)) /* TC0 Interrupt Disable Register */
|
||||
#define AT91C_TC0_CV (AT91_REG(0xFFFA0010)) /* TC0 Counter Value */
|
||||
#define AT91C_TC0_IMR (AT91_REG(0xFFFA002C)) /* TC0 Interrupt Mask Register */
|
||||
|
||||
/* ========== Register definition for TC1 peripheral ========== */
|
||||
#define AT91C_TC1_RB (AT91_REG(0xFFFA0058)) /* TC1 Register B */
|
||||
#define AT91C_TC1_CCR (AT91_REG(0xFFFA0040)) /* TC1 Channel Control Register */
|
||||
#define AT91C_TC1_IER (AT91_REG(0xFFFA0064)) /* TC1 Interrupt Enable Register */
|
||||
#define AT91C_TC1_IDR (AT91_REG(0xFFFA0068)) /* TC1 Interrupt Disable Register */
|
||||
#define AT91C_TC1_SR (AT91_REG(0xFFFA0060)) /* TC1 Status Register */
|
||||
#define AT91C_TC1_CMR (AT91_REG(0xFFFA0044)) /* TC1 Channel Mode Register (Capture Mode / Waveform Mode) */
|
||||
#define AT91C_TC1_RA (AT91_REG(0xFFFA0054)) /* TC1 Register A */
|
||||
#define AT91C_TC1_RC (AT91_REG(0xFFFA005C)) /* TC1 Register C */
|
||||
#define AT91C_TC1_IMR (AT91_REG(0xFFFA006C)) /* TC1 Interrupt Mask Register */
|
||||
#define AT91C_TC1_CV (AT91_REG(0xFFFA0050)) /* TC1 Counter Value */
|
||||
|
||||
/* ========== Register definition for TC2 peripheral ========== */
|
||||
#define AT91C_TC2_CMR (AT91_REG(0xFFFA0084)) /* TC2 Channel Mode Register (Capture Mode / Waveform Mode) */
|
||||
#define AT91C_TC2_CCR (AT91_REG(0xFFFA0080)) /* TC2 Channel Control Register */
|
||||
#define AT91C_TC2_CV (AT91_REG(0xFFFA0090)) /* TC2 Counter Value */
|
||||
#define AT91C_TC2_RA (AT91_REG(0xFFFA0094)) /* TC2 Register A */
|
||||
#define AT91C_TC2_RB (AT91_REG(0xFFFA0098)) /* TC2 Register B */
|
||||
#define AT91C_TC2_IDR (AT91_REG(0xFFFA00A8)) /* TC2 Interrupt Disable Register */
|
||||
#define AT91C_TC2_IMR (AT91_REG(0xFFFA00AC)) /* TC2 Interrupt Mask Register */
|
||||
#define AT91C_TC2_RC (AT91_REG(0xFFFA009C)) /* TC2 Register C */
|
||||
#define AT91C_TC2_IER (AT91_REG(0xFFFA00A4)) /* TC2 Interrupt Enable Register */
|
||||
#define AT91C_TC2_SR (AT91_REG(0xFFFA00A0)) /* TC2 Status Register */
|
||||
|
||||
/* ========== Register definition for PITC peripheral ========== */
|
||||
#define AT91C_PITC_PIVR (AT91_REG(0xFFFFFD38)) /* PITC Period Interval Value Register */
|
||||
#define AT91C_PITC_PISR (AT91_REG(0xFFFFFD34)) /* PITC Period Interval Status Register */
|
||||
#define AT91C_PITC_PIIR (AT91_REG(0xFFFFFD3C)) /* PITC Period Interval Image Register */
|
||||
#define AT91C_PITC_PIMR (AT91_REG(0xFFFFFD30)) /* PITC Period Interval Mode Register */
|
||||
|
||||
/* ========== Register definition for UDP peripheral ========== */
|
||||
#define AT91C_UDP_NUM (AT91_REG(0xFFFB0000)) /* UDP Frame Number Register */
|
||||
#define AT91C_UDP_STAT (AT91_REG(0xFFFB0004)) /* UDP Global State Register */
|
||||
#define AT91C_UDP_FADDR (AT91_REG(0xFFFB0008)) /* UDP Function Address Register */
|
||||
#define AT91C_UDP_IER (AT91_REG(0xFFFB0010)) /* UDP Interrupt Enable Register */
|
||||
#define AT91C_UDP_IDR (AT91_REG(0xFFFB0014)) /* UDP Interrupt Disable Register */
|
||||
#define AT91C_UDP_IMR (AT91_REG(0xFFFB0018)) /* UDP Interrupt Mask Register */
|
||||
#define AT91C_UDP_ISR (AT91_REG(0xFFFB001C)) /* UDP Interrupt Status Register */
|
||||
#define AT91C_UDP_ICR (AT91_REG(0xFFFB0020)) /* UDP Interrupt Clear Register */
|
||||
#define AT91C_UDP_RSTEP (AT91_REG(0xFFFB0028)) /* UDP Reset Endpoint Register */
|
||||
#define AT91C_UDP_CSR0 (AT91_REG(0xFFFB0030)) /* UDP Endpoint Control and Status Register */
|
||||
#define AT91C_UDP_CSR(n) (*(&AT91C_UDP_CSR0 + n))
|
||||
#define AT91C_UDP_FDR0 (AT91_REG(0xFFFB0050)) /* UDP Endpoint FIFO Data Register */
|
||||
#define AT91C_UDP_FDR(n) (*(&AT91C_UDP_FDR0 + n))
|
||||
#define AT91C_UDP_TXVC (AT91_REG(0xFFFB0074)) /* UDP Transceiver Control Register */
|
||||
|
||||
/* ========== Register definition for US0 peripheral ========== */
|
||||
#define AT91C_US0_CR (AT91_REG(0xFFFC0000)) /* US0 Control Register */
|
||||
#define AT91C_US0_MR (AT91_REG(0xFFFC0004)) /* US0 Mode Register */
|
||||
#define AT91C_US0_IER (AT91_REG(0xFFFC0008)) /* US0 Interrupt Enable Register */
|
||||
#define AT91C_US0_IDR (AT91_REG(0xFFFC000C)) /* US0 Interrupt Disable Register */
|
||||
#define AT91C_US0_IMR (AT91_REG(0xFFFC0010)) /* US0 Interrupt Mask Register */
|
||||
#define AT91C_US0_CSR (AT91_REG(0xFFFC0014)) /* US0 Channel Status Register */
|
||||
#define AT91C_US0_RHR (AT91_REG(0xFFFC0018)) /* US0 Receiver Holding Register */
|
||||
#define AT91C_US0_THR (AT91_REG(0xFFFC001C)) /* US0 Transmitter Holding Register */
|
||||
#define AT91C_US0_BRGR (AT91_REG(0xFFFC0020)) /* US0 Baud Rate Generator Register */
|
||||
#define AT91C_US0_RTOR (AT91_REG(0xFFFC0024)) /* US0 Receiver Time-out Register */
|
||||
#define AT91C_US0_TTGR (AT91_REG(0xFFFC0028)) /* US0 Transmitter Time-guard Register */
|
||||
#define AT91C_US0_NER (AT91_REG(0xFFFC0044)) /* US0 Nb Errors Register */
|
||||
#define AT91C_US0_FIDI (AT91_REG(0xFFFC0040)) /* US0 FI_DI_Ratio Register */
|
||||
#define AT91C_US0_IF (AT91_REG(0xFFFC004C)) /* US0 IRDA_FILTER Register */
|
||||
|
||||
/* ========== Register definition for AIC peripheral ========== */
|
||||
#define AT91C_AIC_SMR0 (AT91_REG(0xFFFFF000)) /* AIC Source Mode Register */
|
||||
#define AT91C_AIC_SMR(n) (*(&AT91C_AIC_SMR0 + n))
|
||||
#define AT91C_AIC_SVR0 (AT91_REG(0xFFFFF080)) /* AIC Source Vector Register */
|
||||
#define AT91C_AIC_SVR(n) (*(&AT91C_AIC_SVR0 + n))
|
||||
#define AT91C_AIC_IVR (AT91_REG(0xFFFFF100)) /* AIC Interrupt Vector Register */
|
||||
#define AT91C_AIC_FVR (AT91_REG(0xFFFFF104)) /* AIC FIQ Vector Register */
|
||||
#define AT91C_AIC_ISR (AT91_REG(0xFFFFF108)) /* AIC Interrupt Status Register */
|
||||
#define AT91C_AIC_IPR (AT91_REG(0xFFFFF10C)) /* AIC Interrupt Pending Register */
|
||||
#define AT91C_AIC_IMR (AT91_REG(0xFFFFF110)) /* AIC Interrupt Mask Register */
|
||||
#define AT91C_AIC_CISR (AT91_REG(0xFFFFF114)) /* AIC Core Interrupt Status Register */
|
||||
#define AT91C_AIC_IECR (AT91_REG(0xFFFFF120)) /* AIC Interrupt Enable Command Register */
|
||||
#define AT91C_AIC_IDCR (AT91_REG(0xFFFFF124)) /* AIC Interrupt Disable Command Register */
|
||||
#define AT91C_AIC_ICCR (AT91_REG(0xFFFFF128)) /* AIC Interrupt Clear Command Register */
|
||||
#define AT91C_AIC_ISCR (AT91_REG(0xFFFFF12C)) /* AIC Interrupt Set Command Register */
|
||||
#define AT91C_AIC_EOICR (AT91_REG(0xFFFFF130)) /* AIC End of Interrupt Command Register */
|
||||
#define AT91C_AIC_SPU (AT91_REG(0xFFFFF134)) /* AIC Spurious Vector Register */
|
||||
#define AT91C_AIC_DCR (AT91_REG(0xFFFFF138)) /* AIC Debug Control Register (Protect) */
|
||||
#define AT91C_AIC_FFER (AT91_REG(0xFFFFF140)) /* AIC Fast Forcing Enable Register */
|
||||
#define AT91C_AIC_FFDR (AT91_REG(0xFFFFF144)) /* AIC Fast Forcing Disable Register */
|
||||
#define AT91C_AIC_FFSR (AT91_REG(0xFFFFF148)) /* AIC Fast Forcing Status Register */
|
||||
|
||||
|
||||
/* ========== Register definition for DBGU peripheral ========== */
|
||||
#define AT91C_DBGU_EXID (AT91_REG(0xFFFFF244)) /* DBGU Chip ID Extension Register */
|
||||
#define AT91C_DBGU_BRGR (AT91_REG(0xFFFFF220)) /* DBGU Baud Rate Generator Register */
|
||||
#define AT91C_DBGU_IDR (AT91_REG(0xFFFFF20C)) /* DBGU Interrupt Disable Register */
|
||||
#define AT91C_DBGU_CSR (AT91_REG(0xFFFFF214)) /* DBGU Channel Status Register */
|
||||
#define AT91C_DBGU_CIDR (AT91_REG(0xFFFFF240)) /* DBGU Chip ID Register */
|
||||
#define AT91C_DBGU_MR (AT91_REG(0xFFFFF204)) /* DBGU Mode Register */
|
||||
#define AT91C_DBGU_IMR (AT91_REG(0xFFFFF210)) /* DBGU Interrupt Mask Register */
|
||||
#define AT91C_DBGU_CR (AT91_REG(0xFFFFF200)) /* DBGU Control Register */
|
||||
#define AT91C_DBGU_FNTR (AT91_REG(0xFFFFF248)) /* DBGU Force NTRST Register */
|
||||
#define AT91C_DBGU_THR (AT91_REG(0xFFFFF21C)) /* DBGU Transmitter Holding Register */
|
||||
#define AT91C_DBGU_RHR (AT91_REG(0xFFFFF218)) /* DBGU Receiver Holding Register */
|
||||
#define AT91C_DBGU_IER (AT91_REG(0xFFFFF208)) /* DBGU Interrupt Enable Register */
|
||||
|
||||
/* ========== Register definition for PIO peripheral ========== */
|
||||
#define AT91C_PIO_ODR (AT91_REG(0xFFFFF414)) /* PIOA Output Disable Registerr */
|
||||
#define AT91C_PIO_SODR (AT91_REG(0xFFFFF430)) /* PIOA Set Output Data Register */
|
||||
#define AT91C_PIO_ISR (AT91_REG(0xFFFFF44C)) /* PIOA Interrupt Status Register */
|
||||
#define AT91C_PIO_ABSR (AT91_REG(0xFFFFF478)) /* PIOA AB Select Status Register */
|
||||
#define AT91C_PIO_IER (AT91_REG(0xFFFFF440)) /* PIOA Interrupt Enable Register */
|
||||
#define AT91C_PIO_PPUDR (AT91_REG(0xFFFFF460)) /* PIOA Pull-up Disable Register */
|
||||
#define AT91C_PIO_IMR (AT91_REG(0xFFFFF448)) /* PIOA Interrupt Mask Register */
|
||||
#define AT91C_PIO_PER (AT91_REG(0xFFFFF400)) /* PIOA PIO Enable Register */
|
||||
#define AT91C_PIO_IFDR (AT91_REG(0xFFFFF424)) /* PIOA Input Filter Disable Register */
|
||||
#define AT91C_PIO_OWDR (AT91_REG(0xFFFFF4A4)) /* PIOA Output Write Disable Register */
|
||||
#define AT91C_PIO_MDSR (AT91_REG(0xFFFFF458)) /* PIOA Multi-driver Status Register */
|
||||
#define AT91C_PIO_IDR (AT91_REG(0xFFFFF444)) /* PIOA Interrupt Disable Register */
|
||||
#define AT91C_PIO_ODSR (AT91_REG(0xFFFFF438)) /* PIOA Output Data Status Register */
|
||||
#define AT91C_PIO_PPUSR (AT91_REG(0xFFFFF468)) /* PIOA Pull-up Status Register */
|
||||
#define AT91C_PIO_OWSR (AT91_REG(0xFFFFF4A8)) /* PIOA Output Write Status Register */
|
||||
#define AT91C_PIO_BSR (AT91_REG(0xFFFFF474)) /* PIOA Select B Register */
|
||||
#define AT91C_PIO_OWER (AT91_REG(0xFFFFF4A0)) /* PIOA Output Write Enable Register */
|
||||
#define AT91C_PIO_IFER (AT91_REG(0xFFFFF420)) /* PIOA Input Filter Enable Register */
|
||||
#define AT91C_PIO_PDSR (AT91_REG(0xFFFFF43C)) /* PIOA Pin Data Status Register */
|
||||
#define AT91C_PIO_PPUER (AT91_REG(0xFFFFF464)) /* PIOA Pull-up Enable Register */
|
||||
#define AT91C_PIO_OSR (AT91_REG(0xFFFFF418)) /* PIOA Output Status Register */
|
||||
#define AT91C_PIO_ASR (AT91_REG(0xFFFFF470)) /* PIOA Select A Register */
|
||||
#define AT91C_PIO_MDDR (AT91_REG(0xFFFFF454)) /* PIOA Multi-driver Disable Register */
|
||||
#define AT91C_PIO_CODR (AT91_REG(0xFFFFF434)) /* PIOA Clear Output Data Register */
|
||||
#define AT91C_PIO_MDER (AT91_REG(0xFFFFF450)) /* PIOA Multi-driver Enable Register */
|
||||
#define AT91C_PIO_PDR (AT91_REG(0xFFFFF404)) /* PIOA PIO Disable Register */
|
||||
#define AT91C_PIO_IFSR (AT91_REG(0xFFFFF428)) /* PIOA Input Filter Status Register */
|
||||
#define AT91C_PIO_OER (AT91_REG(0xFFFFF410)) /* PIOA Output Enable Register */
|
||||
#define AT91C_PIO_PSR (AT91_REG(0xFFFFF408)) /* PIOA PIO Status Register */
|
||||
|
||||
// ========== Register definition for PIOA peripheral ==========
|
||||
#define AT91C_PIOA_IMR (AT91_REG(0xFFFFF448)) // (PIOA) Interrupt Mask Register
|
||||
#define AT91C_PIOA_IER (AT91_REG(0xFFFFF440)) // (PIOA) Interrupt Enable Register
|
||||
#define AT91C_PIOA_OWDR (AT91_REG(0xFFFFF4A4)) // (PIOA) Output Write Disable Register
|
||||
#define AT91C_PIOA_ISR (AT91_REG(0xFFFFF44C)) // (PIOA) Interrupt Status Register
|
||||
#define AT91C_PIOA_PPUDR (AT91_REG(0xFFFFF460)) // (PIOA) Pull-up Disable Register
|
||||
#define AT91C_PIOA_MDSR (AT91_REG(0xFFFFF458)) // (PIOA) Multi-driver Status Register
|
||||
#define AT91C_PIOA_MDER (AT91_REG(0xFFFFF450)) // (PIOA) Multi-driver Enable Register
|
||||
#define AT91C_PIOA_PER (AT91_REG(0xFFFFF400)) // (PIOA) PIO Enable Register
|
||||
#define AT91C_PIOA_PSR (AT91_REG(0xFFFFF408)) // (PIOA) PIO Status Register
|
||||
#define AT91C_PIOA_OER (AT91_REG(0xFFFFF410)) // (PIOA) Output Enable Register
|
||||
#define AT91C_PIOA_BSR (AT91_REG(0xFFFFF474)) // (PIOA) Select B Register
|
||||
#define AT91C_PIOA_PPUER (AT91_REG(0xFFFFF464)) // (PIOA) Pull-up Enable Register
|
||||
#define AT91C_PIOA_MDDR (AT91_REG(0xFFFFF454)) // (PIOA) Multi-driver Disable Register
|
||||
#define AT91C_PIOA_PDR (AT91_REG(0xFFFFF404)) // (PIOA) PIO Disable Register
|
||||
#define AT91C_PIOA_ODR (AT91_REG(0xFFFFF414)) // (PIOA) Output Disable Registerr
|
||||
#define AT91C_PIOA_IFDR (AT91_REG(0xFFFFF424)) // (PIOA) Input Filter Disable Register
|
||||
#define AT91C_PIOA_ABSR (AT91_REG(0xFFFFF478)) // (PIOA) AB Select Status Register
|
||||
#define AT91C_PIOA_ASR (AT91_REG(0xFFFFF470)) // (PIOA) Select A Register
|
||||
#define AT91C_PIOA_PPUSR (AT91_REG(0xFFFFF468)) // (PIOA) Pull-up Status Register
|
||||
#define AT91C_PIOA_ODSR (AT91_REG(0xFFFFF438)) // (PIOA) Output Data Status Register
|
||||
#define AT91C_PIOA_SODR (AT91_REG(0xFFFFF430)) // (PIOA) Set Output Data Register
|
||||
#define AT91C_PIOA_IFSR (AT91_REG(0xFFFFF428)) // (PIOA) Input Filter Status Register
|
||||
#define AT91C_PIOA_IFER (AT91_REG(0xFFFFF420)) // (PIOA) Input Filter Enable Register
|
||||
#define AT91C_PIOA_OSR (AT91_REG(0xFFFFF418)) // (PIOA) Output Status Register
|
||||
#define AT91C_PIOA_IDR (AT91_REG(0xFFFFF444)) // (PIOA) Interrupt Disable Register
|
||||
#define AT91C_PIOA_PDSR (AT91_REG(0xFFFFF43C)) // (PIOA) Pin Data Status Register
|
||||
#define AT91C_PIOA_CODR (AT91_REG(0xFFFFF434)) // (PIOA) Clear Output Data Register
|
||||
#define AT91C_PIOA_OWSR (AT91_REG(0xFFFFF4A8)) // (PIOA) Output Write Status Register
|
||||
#define AT91C_PIOA_OWER (AT91_REG(0xFFFFF4A0)) // (PIOA) Output Write Enable Register
|
||||
// ========== Register definition for PIOB peripheral ==========
|
||||
#define AT91C_PIOB_OWSR (AT91_REG(0xFFFFF6A8)) // (PIOB) Output Write Status Register
|
||||
#define AT91C_PIOB_PPUSR (AT91_REG(0xFFFFF668)) // (PIOB) Pull-up Status Register
|
||||
#define AT91C_PIOB_PPUDR (AT91_REG(0xFFFFF660)) // (PIOB) Pull-up Disable Register
|
||||
#define AT91C_PIOB_MDSR (AT91_REG(0xFFFFF658)) // (PIOB) Multi-driver Status Register
|
||||
#define AT91C_PIOB_MDER (AT91_REG(0xFFFFF650)) // (PIOB) Multi-driver Enable Register
|
||||
#define AT91C_PIOB_IMR (AT91_REG(0xFFFFF648)) // (PIOB) Interrupt Mask Register
|
||||
#define AT91C_PIOB_OSR (AT91_REG(0xFFFFF618)) // (PIOB) Output Status Register
|
||||
#define AT91C_PIOB_OER (AT91_REG(0xFFFFF610)) // (PIOB) Output Enable Register
|
||||
#define AT91C_PIOB_PSR (AT91_REG(0xFFFFF608)) // (PIOB) PIO Status Register
|
||||
#define AT91C_PIOB_PER (AT91_REG(0xFFFFF600)) // (PIOB) PIO Enable Register
|
||||
#define AT91C_PIOB_BSR (AT91_REG(0xFFFFF674)) // (PIOB) Select B Register
|
||||
#define AT91C_PIOB_PPUER (AT91_REG(0xFFFFF664)) // (PIOB) Pull-up Enable Register
|
||||
#define AT91C_PIOB_IFDR (AT91_REG(0xFFFFF624)) // (PIOB) Input Filter Disable Register
|
||||
#define AT91C_PIOB_ODR (AT91_REG(0xFFFFF614)) // (PIOB) Output Disable Registerr
|
||||
#define AT91C_PIOB_ABSR (AT91_REG(0xFFFFF678)) // (PIOB) AB Select Status Register
|
||||
#define AT91C_PIOB_ASR (AT91_REG(0xFFFFF670)) // (PIOB) Select A Register
|
||||
#define AT91C_PIOB_IFER (AT91_REG(0xFFFFF620)) // (PIOB) Input Filter Enable Register
|
||||
#define AT91C_PIOB_IFSR (AT91_REG(0xFFFFF628)) // (PIOB) Input Filter Status Register
|
||||
#define AT91C_PIOB_SODR (AT91_REG(0xFFFFF630)) // (PIOB) Set Output Data Register
|
||||
#define AT91C_PIOB_ODSR (AT91_REG(0xFFFFF638)) // (PIOB) Output Data Status Register
|
||||
#define AT91C_PIOB_CODR (AT91_REG(0xFFFFF634)) // (PIOB) Clear Output Data Register
|
||||
#define AT91C_PIOB_PDSR (AT91_REG(0xFFFFF63C)) // (PIOB) Pin Data Status Register
|
||||
#define AT91C_PIOB_OWER (AT91_REG(0xFFFFF6A0)) // (PIOB) Output Write Enable Register
|
||||
#define AT91C_PIOB_IER (AT91_REG(0xFFFFF640)) // (PIOB) Interrupt Enable Register
|
||||
#define AT91C_PIOB_OWDR (AT91_REG(0xFFFFF6A4)) // (PIOB) Output Write Disable Register
|
||||
#define AT91C_PIOB_MDDR (AT91_REG(0xFFFFF654)) // (PIOB) Multi-driver Disable Register
|
||||
#define AT91C_PIOB_ISR (AT91_REG(0xFFFFF64C)) // (PIOB) Interrupt Status Register
|
||||
#define AT91C_PIOB_IDR (AT91_REG(0xFFFFF644)) // (PIOB) Interrupt Disable Register
|
||||
#define AT91C_PIOB_PDR (AT91_REG(0xFFFFF604)) // (PIOB) PIO Disable Register
|
||||
|
||||
/* ========== Register definition for PMC peripheral ========== */
|
||||
#define AT91C_PMC_SCER (AT91_REG(0xFFFFFC00)) /* PMC System Clock Enable Register */
|
||||
#define AT91C_PMC_SCDR (AT91_REG(0xFFFFFC04)) /* PMC System Clock Disable Register */
|
||||
#define AT91C_PMC_SCSR (AT91_REG(0xFFFFFC08)) /* PMC System Clock Status Register */
|
||||
#define AT91C_PMC_PCER (AT91_REG(0xFFFFFC10)) /* PMC Peripheral Clock Enable Register */
|
||||
#define AT91C_PMC_PCDR (AT91_REG(0xFFFFFC14)) /* PMC Peripheral Clock Disable Register */
|
||||
#define AT91C_PMC_PCSR (AT91_REG(0xFFFFFC18)) /* PMC Peripheral Clock Status Register */
|
||||
#define AT91C_PMC_MOR (AT91_REG(0xFFFFFC20)) /* PMC Main Oscillator Register */
|
||||
#define AT91C_PMC_MCFR (AT91_REG(0xFFFFFC24)) /* PMC Main Clock Frequency Register */
|
||||
#define AT91C_PMC_PLLR (AT91_REG(0xFFFFFC2C)) /* PMC PLL Register */
|
||||
#define AT91C_PMC_MCKR (AT91_REG(0xFFFFFC30)) /* PMC Master Clock Register */
|
||||
#define AT91C_PMC_PCKR (AT91_REG(0xFFFFFC40)) /* PMC Programmable Clock Register */
|
||||
#define AT91C_PMC_IER (AT91_REG(0xFFFFFC60)) /* PMC Interrupt Enable Register */
|
||||
#define AT91C_PMC_IDR (AT91_REG(0xFFFFFC64)) /* PMC Interrupt Disable Register */
|
||||
#define AT91C_PMC_SR (AT91_REG(0xFFFFFC68)) /* PMC Status Register */
|
||||
#define AT91C_PMC_IMR (AT91_REG(0xFFFFFC6C)) /* PMC Interrupt Mask Register */
|
||||
|
||||
/******************************************************************************/
|
||||
/* PERIPHERAL ID DEFINITIONS FOR AT91SAM7S64 */
|
||||
/******************************************************************************/
|
||||
#define AT91C_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
|
||||
#define AT91C_ID_SYS 1 /* System Peripheral */
|
||||
#define AT91C_ID_PIOA 2 /* Parallel IO Controller A */
|
||||
#define AT91C_ID_PIOB 3 /* Parallel IO Controller B */
|
||||
#define AT91C_ID_ADC 4 /* Analog-to-Digital Converter */
|
||||
#define AT91C_ID_SPI 5 /* Serial Peripheral Interface */
|
||||
#define AT91C_ID_US0 6 /* USART 0 */
|
||||
#define AT91C_ID_US1 7 /* USART 1 */
|
||||
#define AT91C_ID_SSC 8 /* Serial Synchronous Controller */
|
||||
#define AT91C_ID_TWI 9 /* Two-Wire Interface */
|
||||
#define AT91C_ID_PWMC 10 /* PWM Controller */
|
||||
#define AT91C_ID_UDP 11 /* USB Device Port */
|
||||
#define AT91C_ID_TC0 12 /* Timer Counter 0 */
|
||||
#define AT91C_ID_TC1 13 /* Timer Counter 1 */
|
||||
#define AT91C_ID_TC2 14 /* Timer Counter 2 */
|
||||
#define AT91C_ID_15 15 /* Reserved */
|
||||
#define AT91C_ID_16 16 /* Reserved */
|
||||
#define AT91C_ID_17 17 /* Reserved */
|
||||
#define AT91C_ID_18 18 /* Reserved */
|
||||
#define AT91C_ID_19 19 /* Reserved */
|
||||
#define AT91C_ID_20 20 /* Reserved */
|
||||
#define AT91C_ID_21 21 /* Reserved */
|
||||
#define AT91C_ID_22 22 /* Reserved */
|
||||
#define AT91C_ID_23 23 /* Reserved */
|
||||
#define AT91C_ID_24 24 /* Reserved */
|
||||
#define AT91C_ID_25 25 /* Reserved */
|
||||
#define AT91C_ID_26 26 /* Reserved */
|
||||
#define AT91C_ID_27 27 /* Reserved */
|
||||
#define AT91C_ID_28 28 /* Reserved */
|
||||
#define AT91C_ID_29 29 /* Reserved */
|
||||
#define AT91C_ID_IRQ0 30 /* Advanced Interrupt Controller (IRQ0) */
|
||||
#define AT91C_ID_IRQ1 31 /* Advanced Interrupt Controller (IRQ1) */
|
||||
#define AT91C_ALL_INT 0xC0007FF7 /* ALL VALID INTERRUPTS */
|
||||
|
||||
/*****************************/
|
||||
/* CPU Mode */
|
||||
/*****************************/
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-13 Bernard first version
|
||||
*/
|
||||
|
||||
#define NOINT 0xc0
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable()/*
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
mrs r0, cpsr
|
||||
orr r1, r0, #NOINT
|
||||
msr cpsr_c, r1
|
||||
mov pc, lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level)/*
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
msr cpsr, r0
|
||||
mov pc, lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to)/*
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
stmfd sp!, {lr} /* push pc (lr should be pushed in place of PC) */
|
||||
stmfd sp!, {r0-r12, lr} /* push lr & register file */
|
||||
|
||||
mrs r4, cpsr
|
||||
stmfd sp!, {r4} /* push cpsr */
|
||||
mrs r4, spsr
|
||||
stmfd sp!, {r4} /* push spsr */
|
||||
|
||||
str sp, [r0] /* store sp in preempted tasks TCB */
|
||||
ldr sp, [r1] /* get new task stack pointer */
|
||||
|
||||
ldmfd sp!, {r4} /* pop new task spsr */
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r4} /* pop new task cpsr */
|
||||
msr cpsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to)/*
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
ldr sp, [r0] /* get new task stack pointer */
|
||||
|
||||
ldmfd sp!, {r4} /* pop new task spsr */
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r4} /* pop new task cpsr */
|
||||
msr cpsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to)/*
|
||||
*/
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
mov r3, #1 /* set rt_thread_switch_interrupt_flag to 1 */
|
||||
str r3, [r2]
|
||||
ldr r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
str r0, [r2]
|
||||
_reswitch:
|
||||
ldr r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
str r1, [r2]
|
||||
mov pc, lr
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-01-20 Bernard first version
|
||||
*/
|
||||
|
||||
NOINT EQU 0xc0 ; disable interrupt in psr
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
ARM
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, cpsr
|
||||
ORR r1, r0, #NOINT
|
||||
MSR cpsr_c, r1
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR cpsr_c, r0
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC)
|
||||
STMFD sp!, {r0-r12, lr} ; push lr & register file
|
||||
|
||||
MRS r4, cpsr
|
||||
STMFD sp!, {r4} ; push cpsr
|
||||
MRS r4, spsr
|
||||
STMFD sp!, {r4} ; push spsr
|
||||
|
||||
STR sp, [r0] ; store sp in preempted tasks TCB
|
||||
LDR sp, [r1] ; get new task stack pointer
|
||||
|
||||
LDMFD sp!, {r4} ; pop new task spsr
|
||||
MSR spsr_cxsf, r4
|
||||
LDMFD sp!, {r4} ; pop new task cpsr
|
||||
MSR cpsr_cxsf, r4
|
||||
|
||||
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
LDR sp, [r0] ; get new task stack pointer
|
||||
|
||||
LDMFD sp!, {r4} ; pop new task spsr
|
||||
MSR spsr_cxsf, r4
|
||||
LDMFD sp!, {r4} ; pop new task cpsr
|
||||
MSR cpsr_cxsf, r4
|
||||
|
||||
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
; */
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
rt_hw_context_switch_interrupt PROC
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1
|
||||
STR r3, [r2]
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
END
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "AT91SAM7S.h"
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* this function will reset CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "AT91SAM7S.h"
|
||||
|
||||
#define MAX_HANDLERS 32
|
||||
|
||||
extern rt_uint32_t rt_interrupt_nest;
|
||||
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
void rt_hw_interrupt_handler(int vector)
|
||||
{
|
||||
rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
*/
|
||||
void rt_hw_interrupt_init()
|
||||
{
|
||||
rt_base_t index;
|
||||
|
||||
for (index = 0; index < MAX_HANDLERS; index ++)
|
||||
{
|
||||
AT91C_AIC_SVR(index) = (rt_uint32_t)rt_hw_interrupt_handler;
|
||||
}
|
||||
|
||||
/* init interrupt nest, and context in thread sp */
|
||||
rt_interrupt_nest = 0;
|
||||
rt_interrupt_from_thread = 0;
|
||||
rt_interrupt_to_thread = 0;
|
||||
rt_thread_switch_interrupt_flag = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_mask(int vector)
|
||||
{
|
||||
/* disable interrupt */
|
||||
AT91C_AIC_IDCR = 1 << vector;
|
||||
|
||||
/* clear interrupt */
|
||||
AT91C_AIC_ICCR = 1 << vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will un-mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
AT91C_AIC_IECR = 1 << vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param new_handler the interrupt service routine to be installed
|
||||
* @param old_handler the old interrupt service routine
|
||||
*/
|
||||
void rt_hw_interrupt_install(int vector, rt_isr_handler_t new_handler, rt_isr_handler_t *old_handler)
|
||||
{
|
||||
if(vector >= 0 && vector < MAX_HANDLERS)
|
||||
{
|
||||
if (*old_handler != RT_NULL) *old_handler = (rt_isr_handler_t)AT91C_AIC_SVR(vector);
|
||||
if (new_handler != RT_NULL) AT91C_AIC_SVR(vector) = (rt_uint32_t)new_handler;
|
||||
}
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard first version
|
||||
* 2009-05-14 Bernard add RT-THread device interface
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "AT91SAM7S.h"
|
||||
#include "serial.h"
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
typedef volatile rt_uint32_t REG32;
|
||||
struct rt_at91serial_hw
|
||||
{
|
||||
REG32 US_CR; // Control Register
|
||||
REG32 US_MR; // Mode Register
|
||||
REG32 US_IER; // Interrupt Enable Register
|
||||
REG32 US_IDR; // Interrupt Disable Register
|
||||
REG32 US_IMR; // Interrupt Mask Register
|
||||
REG32 US_CSR; // Channel Status Register
|
||||
REG32 US_RHR; // Receiver Holding Register
|
||||
REG32 US_THR; // Transmitter Holding Register
|
||||
REG32 US_BRGR; // Baud Rate Generator Register
|
||||
REG32 US_RTOR; // Receiver Time-out Register
|
||||
REG32 US_TTGR; // Transmitter Time-guard Register
|
||||
REG32 Reserved0[5]; //
|
||||
REG32 US_FIDI; // FI_DI_Ratio Register
|
||||
REG32 US_NER; // Nb Errors Register
|
||||
REG32 Reserved1[1]; //
|
||||
REG32 US_IF; // IRDA_FILTER Register
|
||||
REG32 Reserved2[44]; //
|
||||
REG32 US_RPR; // Receive Pointer Register
|
||||
REG32 US_RCR; // Receive Counter Register
|
||||
REG32 US_TPR; // Transmit Pointer Register
|
||||
REG32 US_TCR; // Transmit Counter Register
|
||||
REG32 US_RNPR; // Receive Next Pointer Register
|
||||
REG32 US_RNCR; // Receive Next Counter Register
|
||||
REG32 US_TNPR; // Transmit Next Pointer Register
|
||||
REG32 US_TNCR; // Transmit Next Counter Register
|
||||
REG32 US_PTCR; // PDC Transfer Control Register
|
||||
REG32 US_PTSR; // PDC Transfer Status Register
|
||||
};
|
||||
|
||||
struct rt_at91serial
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
struct rt_at91serial_hw* hw_base;
|
||||
rt_uint16_t peripheral_id;
|
||||
rt_uint32_t baudrate;
|
||||
|
||||
/* reception field */
|
||||
rt_uint16_t save_index, read_index;
|
||||
rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE];
|
||||
};
|
||||
#ifdef RT_USING_UART1
|
||||
struct rt_at91serial serial1;
|
||||
#endif
|
||||
#ifdef RT_USING_UART2
|
||||
struct rt_at91serial serial2;
|
||||
#endif
|
||||
|
||||
static void rt_hw_serial_isr(int irqno)
|
||||
{
|
||||
rt_base_t level;
|
||||
struct rt_device* device;
|
||||
struct rt_at91serial* serial = RT_NULL;
|
||||
|
||||
if (irqno == AT91C_ID_US0)
|
||||
{
|
||||
#ifdef RT_USING_UART1
|
||||
/* serial 1 */
|
||||
serial = &serial1;
|
||||
#endif
|
||||
}
|
||||
else if (irqno == AT91C_ID_US1)
|
||||
{
|
||||
#ifdef RT_USING_UART2
|
||||
/* serial 2 */
|
||||
serial = &serial2;
|
||||
#endif
|
||||
}
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
/* get generic device object */
|
||||
device = (rt_device_t)serial;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* get received character */
|
||||
serial->rx_buffer[serial->save_index] = serial->hw_base->US_RHR;
|
||||
|
||||
/* move to next position */
|
||||
serial->save_index ++;
|
||||
if (serial->save_index >= RT_UART_RX_BUFFER_SIZE)
|
||||
serial->save_index = 0;
|
||||
|
||||
/* if the next position is read index, discard this 'read char' */
|
||||
if (serial->save_index == serial->read_index)
|
||||
{
|
||||
serial->read_index ++;
|
||||
if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
|
||||
serial->read_index = 0;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* indicate to upper layer application */
|
||||
if (device->rx_indicate != RT_NULL)
|
||||
device->rx_indicate(device, 1);
|
||||
|
||||
/* ack interrupt */
|
||||
AT91C_AIC_EOICR = 1;
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_init (rt_device_t dev)
|
||||
{
|
||||
rt_uint32_t bd;
|
||||
struct rt_at91serial* serial = (struct rt_at91serial*) dev;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
/* must be US0 or US1 */
|
||||
RT_ASSERT(((serial->peripheral_id == AT91C_ID_US0) ||
|
||||
(serial->peripheral_id == AT91C_ID_US1)));
|
||||
|
||||
/* Enable Clock for USART */
|
||||
AT91C_PMC_PCER = 1 << serial->peripheral_id;
|
||||
|
||||
/* Enable RxD0 and TxDO Pin */
|
||||
if (serial->peripheral_id == AT91C_ID_US0)
|
||||
{
|
||||
/* set pinmux */
|
||||
AT91C_PIO_PDR = (1 << 5) | (1 << 6);
|
||||
}
|
||||
else if (serial->peripheral_id == AT91C_ID_US1)
|
||||
{
|
||||
/* set pinmux */
|
||||
AT91C_PIO_PDR = (1 << 21) | (1 << 22);
|
||||
}
|
||||
|
||||
serial->hw_base->US_CR = AT91C_US_RSTRX | /* Reset Receiver */
|
||||
AT91C_US_RSTTX | /* Reset Transmitter */
|
||||
AT91C_US_RXDIS | /* Receiver Disable */
|
||||
AT91C_US_TXDIS; /* Transmitter Disable */
|
||||
|
||||
serial->hw_base->US_MR = AT91C_US_USMODE_NORMAL | /* Normal Mode */
|
||||
AT91C_US_CLKS_CLOCK | /* Clock = MCK */
|
||||
AT91C_US_CHRL_8_BITS | /* 8-bit Data */
|
||||
AT91C_US_PAR_NONE | /* No Parity */
|
||||
AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */
|
||||
|
||||
/* set baud rate divisor */
|
||||
bd = ((MCK*10)/(serial->baudrate * 16));
|
||||
if ((bd % 10) >= 5) bd = (bd / 10) + 1;
|
||||
else bd /= 10;
|
||||
|
||||
serial->hw_base->US_BRGR = bd;
|
||||
serial->hw_base->US_CR = AT91C_US_RXEN | /* Receiver Enable */
|
||||
AT91C_US_TXEN; /* Transmitter Enable */
|
||||
|
||||
/* reset rx index */
|
||||
serial->save_index = 0;
|
||||
serial->read_index = 0;
|
||||
|
||||
/* reset rx buffer */
|
||||
rt_memset(serial->rx_buffer, 0, RT_UART_RX_BUFFER_SIZE);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
/* enable UART rx interrupt */
|
||||
serial->hw_base->US_IER = 1 << 0; /* RxReady interrupt */
|
||||
serial->hw_base->US_IMR |= 1 << 0; /* umask RxReady interrupt */
|
||||
|
||||
/* install UART handler */
|
||||
rt_hw_interrupt_install(serial->peripheral_id, rt_hw_serial_isr, RT_NULL);
|
||||
AT91C_AIC_SMR(serial->peripheral_id) = 5 | (0x01 << 5);
|
||||
rt_hw_interrupt_umask(serial->peripheral_id);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_close(rt_device_t dev)
|
||||
{
|
||||
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
/* disable interrupt */
|
||||
serial->hw_base->US_IDR = 1 << 0; /* RxReady interrupt */
|
||||
serial->hw_base->US_IMR &= ~(1 << 0); /* mask RxReady interrupt */
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t* ptr;
|
||||
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
/* point to buffer */
|
||||
ptr = (rt_uint8_t*) buffer;
|
||||
|
||||
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
/* interrupt receive */
|
||||
rt_base_t level;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (serial->read_index != serial->save_index)
|
||||
{
|
||||
*ptr = serial->rx_buffer[serial->read_index];
|
||||
|
||||
serial->read_index ++;
|
||||
if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
|
||||
serial->read_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no data in rx buffer */
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
ptr ++; size --;
|
||||
}
|
||||
|
||||
return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
|
||||
}
|
||||
else if (dev->flag & RT_DEVICE_FLAG_DMA_RX)
|
||||
{
|
||||
/* not support right now */
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* poll mode */
|
||||
while (size)
|
||||
{
|
||||
/* Wait for Full Rx Buffer */
|
||||
while (!(serial->hw_base->US_CSR & AT91C_US_RXRDY));
|
||||
|
||||
/* Read Character */
|
||||
*ptr = serial->hw_base->US_RHR;
|
||||
ptr ++;
|
||||
size --;
|
||||
}
|
||||
|
||||
return (rt_size_t)ptr - (rt_size_t)buffer;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_size_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t* ptr;
|
||||
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
ptr = (rt_uint8_t*) buffer;
|
||||
if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
|
||||
{
|
||||
if (dev->flag & RT_DEVICE_FLAG_STREAM)
|
||||
{
|
||||
/* it's a stream mode device */
|
||||
while (size)
|
||||
{
|
||||
/* stream mode */
|
||||
if (*ptr == '\n')
|
||||
{
|
||||
while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
|
||||
serial->hw_base->US_THR = '\r';
|
||||
}
|
||||
|
||||
/* Wait for Empty Tx Buffer */
|
||||
while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
|
||||
|
||||
/* Transmit Character */
|
||||
serial->hw_base->US_THR = *ptr;
|
||||
ptr ++; size --;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
/* Wait for Empty Tx Buffer */
|
||||
while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
|
||||
|
||||
/* Transmit Character */
|
||||
serial->hw_base->US_THR = *ptr;
|
||||
ptr ++; size --;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (rt_size_t)ptr - (rt_size_t)buffer;
|
||||
}
|
||||
|
||||
static rt_err_t rt_serial_control (rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_hw_serial_init()
|
||||
{
|
||||
rt_device_t device;
|
||||
|
||||
#ifdef RT_USING_UART1
|
||||
device = (rt_device_t) &serial1;
|
||||
|
||||
/* init serial device private data */
|
||||
serial1.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US0;
|
||||
serial1.peripheral_id = AT91C_ID_US0;
|
||||
serial1.baudrate = 115200;
|
||||
|
||||
/* set device virtual interface */
|
||||
device->init = rt_serial_init;
|
||||
device->open = rt_serial_open;
|
||||
device->close = rt_serial_close;
|
||||
device->read = rt_serial_read;
|
||||
device->write = rt_serial_write;
|
||||
device->control = rt_serial_control;
|
||||
|
||||
/* register uart1 on device subsystem */
|
||||
rt_device_register(device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_UART2
|
||||
device = (rt_device_t) &serial2;
|
||||
|
||||
serial2.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US1;
|
||||
serial2.peripheral_id = AT91C_ID_US1;
|
||||
serial2.baudrate = 115200;
|
||||
|
||||
/* set device virtual interface */
|
||||
device->init = rt_serial_init;
|
||||
device->open = rt_serial_open;
|
||||
device->close = rt_serial_close;
|
||||
device->read = rt_serial_read;
|
||||
device->write = rt_serial_write;
|
||||
device->control = rt_serial_control;
|
||||
|
||||
/* register uart2 on device subsystem */
|
||||
rt_device_register(device, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __RT_SERIAL_H__
|
||||
#define __RT_SERIAL_H__
|
||||
|
||||
#ifndef AT91C_BASE_US0
|
||||
#define AT91C_BASE_US0 (0xFFFC0000) // (US0) Base Address
|
||||
#endif
|
||||
|
||||
#ifndef AT91C_BASE_US1
|
||||
#define AT91C_BASE_US1 (0xFFFC4000) // (US1) Base Address
|
||||
#endif
|
||||
|
||||
#define AT91C_US_RXRDY ((unsigned int) 0x1 << 0) /* US RXRDY Interrupt */
|
||||
#define AT91C_US_TXRDY ((unsigned int) 0x1 << 1) /* US TXRDY Interrupt */
|
||||
#define AT91C_US_RSTRX ((unsigned int) 0x1 << 2) /* US Reset Receiver */
|
||||
#define AT91C_US_RSTTX ((unsigned int) 0x1 << 3) /* US Reset Transmitter */
|
||||
#define AT91C_US_RXEN ((unsigned int) 0x1 << 4) /* US Receiver Enable */
|
||||
#define AT91C_US_RXDIS ((unsigned int) 0x1 << 5) /* US Receiver Disable */
|
||||
#define AT91C_US_TXEN ((unsigned int) 0x1 << 6) /* US Transmitter Enable */
|
||||
#define AT91C_US_TXDIS ((unsigned int) 0x1 << 7) /* US Transmitter Disable */
|
||||
#define AT91C_US_RSTSTA ((unsigned int) 0x1 << 8) /* US Reset Status Bits */
|
||||
|
||||
#define AT91C_US_USMODE_NORMAL ((unsigned int) 0x0) /* USAR) Normal */
|
||||
#define AT91C_US_USMODE_RS485 ((unsigned int) 0x1) /* USAR) RS485 */
|
||||
#define AT91C_US_USMODE_HWHSH ((unsigned int) 0x2) /* USAR) Hardware Handshaking */
|
||||
#define AT91C_US_USMODE_MODEM ((unsigned int) 0x3) /* USAR) Modem */
|
||||
#define AT91C_US_USMODE_ISO7816_0 ((unsigned int) 0x4) /* USAR) ISO7816 protocol: T = 0 */
|
||||
#define AT91C_US_USMODE_ISO7816_1 ((unsigned int) 0x6) /* USAR) ISO7816 protocol: T = 1 */
|
||||
#define AT91C_US_USMODE_IRDA ((unsigned int) 0x8) /* USAR) IrDA */
|
||||
#define AT91C_US_USMODE_SWHSH ((unsigned int) 0xC) /* USAR) Software Handshaking */
|
||||
|
||||
#define AT91C_US_CLKS_CLOCK ((unsigned int) 0x0 << 4) /* USAR) Clock */
|
||||
#define AT91C_US_CLKS_FDIV1 ((unsigned int) 0x1 << 4) /* USAR) fdiv1 */
|
||||
#define AT91C_US_CLKS_SLOW ((unsigned int) 0x2 << 4) /* USAR) slow_clock (ARM) */
|
||||
#define AT91C_US_CLKS_EXT ((unsigned int) 0x3 << 4) /* USAR) External (SCK) */
|
||||
|
||||
#define AT91C_US_CHRL_5_BITS ((unsigned int) 0x0 << 6) /* USAR) Character Length: 5 bits */
|
||||
#define AT91C_US_CHRL_6_BITS ((unsigned int) 0x1 << 6) /* USAR) Character Length: 6 bits */
|
||||
#define AT91C_US_CHRL_7_BITS ((unsigned int) 0x2 << 6) /* USAR) Character Length: 7 bits */
|
||||
#define AT91C_US_CHRL_8_BITS ((unsigned int) 0x3 << 6) /* USAR) Character Length: 8 bits */
|
||||
|
||||
#define AT91C_US_PAR_EVEN ((unsigned int) 0x0 << 9) /* DBGU Even Parity */
|
||||
#define AT91C_US_PAR_ODD ((unsigned int) 0x1 << 9) /* DBGU Odd Parity */
|
||||
#define AT91C_US_PAR_SPACE ((unsigned int) 0x2 << 9) /* DBGU Parity forced to 0 (Space) */
|
||||
#define AT91C_US_PAR_MARK ((unsigned int) 0x3 << 9) /* DBGU Parity forced to 1 (Mark) */
|
||||
#define AT91C_US_PAR_NONE ((unsigned int) 0x4 << 9) /* DBGU No Parity */
|
||||
#define AT91C_US_PAR_MULTI_DROP ((unsigned int) 0x6 << 9) /* DBGU Multi-drop mode */
|
||||
|
||||
#define AT91C_US_NBSTOP_1_BIT ((unsigned int) 0x0 << 12) /* USART 1 stop bit */
|
||||
#define AT91C_US_NBSTOP_15_BIT ((unsigned int) 0x1 << 12) /* USART Asynchronous (SYNC=0) 2 stop bits Synchronous (SYNC=1) 2 stop bits */
|
||||
#define AT91C_US_NBSTOP_2_BIT ((unsigned int) 0x2 << 12) /* USART 2 stop bits */
|
||||
|
||||
#define MCK 48054857
|
||||
#define BR 115200 /* Baud Rate */
|
||||
#define BRD (MCK/16/BR) /* Baud Rate Divisor */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include "AT91SAM7S.h"
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
*(--stk) = SVCMODE; /* cpsr */
|
||||
*(--stk) = SVCMODE; /* spsr */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-31 Bernard first version
|
||||
*/
|
||||
|
||||
/* Internal Memory Base Addresses */
|
||||
.equ FLASH_BASE, 0x00100000
|
||||
.equ RAM_BASE, 0x00200000
|
||||
|
||||
/* Stack Configuration */
|
||||
.equ TOP_STACK, 0x00204000
|
||||
.equ UND_STACK_SIZE, 0x00000100
|
||||
.equ SVC_STACK_SIZE, 0x00000400
|
||||
.equ ABT_STACK_SIZE, 0x00000100
|
||||
.equ FIQ_STACK_SIZE, 0x00000100
|
||||
.equ IRQ_STACK_SIZE, 0x00000100
|
||||
.equ USR_STACK_SIZE, 0x00000004
|
||||
|
||||
/* ARM architecture definitions */
|
||||
.equ MODE_USR, 0x10
|
||||
.equ MODE_FIQ, 0x11
|
||||
.equ MODE_IRQ, 0x12
|
||||
.equ MODE_SVC, 0x13
|
||||
.equ MODE_ABT, 0x17
|
||||
.equ MODE_UND, 0x1B
|
||||
.equ MODE_SYS, 0x1F
|
||||
|
||||
.equ I_BIT, 0x80 /* when this bit is set, IRQ is disabled */
|
||||
.equ F_BIT, 0x40 /* when this bit is set, FIQ is disabled */
|
||||
|
||||
.section .init, "ax"
|
||||
.code 32
|
||||
.align 0
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
ldr pc, _vector_undef
|
||||
ldr pc, _vector_swi
|
||||
ldr pc, _vector_pabt
|
||||
ldr pc, _vector_dabt
|
||||
nop /* reserved vector */
|
||||
ldr pc, _vector_irq
|
||||
ldr pc, _vector_fiq
|
||||
|
||||
_vector_undef: .word vector_undef
|
||||
_vector_swi: .word vector_swi
|
||||
_vector_pabt: .word vector_pabt
|
||||
_vector_dabt: .word vector_dabt
|
||||
_vector_resv: .word vector_resv
|
||||
_vector_irq: .word vector_irq
|
||||
_vector_fiq: .word vector_fiq
|
||||
|
||||
/*
|
||||
* rtthread bss start and end
|
||||
* which are defined in linker script
|
||||
*/
|
||||
.globl _bss_start
|
||||
_bss_start: .word __bss_start
|
||||
.globl _bss_end
|
||||
_bss_end: .word __bss_end
|
||||
|
||||
/* the system entry */
|
||||
reset:
|
||||
/* disable watchdog */
|
||||
ldr r0, =0xFFFFFD40
|
||||
ldr r1, =0x00008000
|
||||
str r1, [r0, #0x04]
|
||||
|
||||
/* enable the main oscillator */
|
||||
ldr r0, =0xFFFFFC00
|
||||
ldr r1, =0x00000601
|
||||
str r1, [r0, #0x20]
|
||||
|
||||
/* wait for main oscillator to stabilize */
|
||||
moscs_loop:
|
||||
ldr r2, [r0, #0x68]
|
||||
ands r2, r2, #1
|
||||
beq moscs_loop
|
||||
|
||||
/* set up the PLL */
|
||||
ldr r1, =0x00191C05
|
||||
str r1, [r0, #0x2C]
|
||||
|
||||
/* wait for PLL to lock */
|
||||
pll_loop:
|
||||
ldr r2, [r0, #0x68]
|
||||
ands r2, r2, #0x04
|
||||
beq pll_loop
|
||||
|
||||
/* select clock */
|
||||
ldr r1, =0x00000007
|
||||
str r1, [r0, #0x30]
|
||||
|
||||
/* setup stack for each mode */
|
||||
ldr r0, =TOP_STACK
|
||||
|
||||
/* set stack */
|
||||
/* undefined instruction mode */
|
||||
msr cpsr_c, #MODE_UND|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #UND_STACK_SIZE
|
||||
|
||||
/* abort mode */
|
||||
msr cpsr_c, #MODE_ABT|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #ABT_STACK_SIZE
|
||||
|
||||
/* FIQ mode */
|
||||
msr cpsr_c, #MODE_FIQ|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #FIQ_STACK_SIZE
|
||||
|
||||
/* IRQ mode */
|
||||
msr cpsr_c, #MODE_IRQ|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #IRQ_STACK_SIZE
|
||||
|
||||
/* supervisor mode */
|
||||
msr cpsr_c, #MODE_SVC
|
||||
mov sp, r0
|
||||
|
||||
#ifdef __FLASH_BUILD__
|
||||
/* Relocate .data section (Copy from ROM to RAM) */
|
||||
ldr r1, =_etext
|
||||
ldr r2, =_data
|
||||
ldr r3, =_edata
|
||||
data_loop:
|
||||
cmp r2, r3
|
||||
ldrlo r0, [r1], #4
|
||||
strlo r0, [r2], #4
|
||||
blo data_loop
|
||||
#else
|
||||
/* remap SRAM to 0x0000 */
|
||||
ldr r0, =0xFFFFFF00
|
||||
mov r1, #0x01
|
||||
str r1, [r0]
|
||||
#endif
|
||||
|
||||
/* mask all IRQs */
|
||||
ldr r1, =0xFFFFF124
|
||||
ldr r0, =0XFFFFFFFF
|
||||
str r0, [r1]
|
||||
|
||||
/* start RT-Thread Kernel */
|
||||
ldr pc, _rtthread_startup
|
||||
|
||||
_rtthread_startup: .word rtthread_startup
|
||||
|
||||
/* exception handlers */
|
||||
vector_undef: b vector_undef
|
||||
vector_swi : b vector_swi
|
||||
vector_pabt : b vector_pabt
|
||||
vector_dabt : b vector_dabt
|
||||
vector_resv : b vector_resv
|
||||
|
||||
.globl rt_interrupt_enter
|
||||
.globl rt_interrupt_leave
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
vector_irq:
|
||||
stmfd sp!, {r0-r12,lr}
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
/*
|
||||
* if rt_thread_switch_interrupt_flag set, jump to
|
||||
* rt_hw_context_switch_interrupt_do and don't return
|
||||
*/
|
||||
ldr r0, =rt_thread_switch_interrupt_flag
|
||||
ldr r1, [r0]
|
||||
cmp r1, #1
|
||||
beq rt_hw_context_switch_interrupt_do
|
||||
|
||||
ldmfd sp!, {r0-r12,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
vector_fiq:
|
||||
stmfd sp!,{r0-r7,lr}
|
||||
bl rt_hw_trap_fiq
|
||||
ldmfd sp!,{r0-r7,lr}
|
||||
subs pc,lr,#4
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt_do(rt_base_t flag)
|
||||
*/
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
mov r1, #0 /* clear flag */
|
||||
str r1, [r0]
|
||||
|
||||
ldmfd sp!, {r0-r12,lr} /* reload saved registers */
|
||||
stmfd sp!, {r0-r3} /* save r0-r3 */
|
||||
mov r1, sp
|
||||
add sp, sp, #16 /* restore sp */
|
||||
sub r2, lr, #4 /* save old task's pc to r2 */
|
||||
|
||||
mrs r3, spsr /* disable interrupt */
|
||||
orr r0, r3, #I_BIT|F_BIT
|
||||
msr spsr_c, r0
|
||||
|
||||
ldr r0, =.+8 /* switch to interrupted task's stack */
|
||||
movs pc, r0
|
||||
|
||||
stmfd sp!, {r2} /* push old task's pc */
|
||||
stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */
|
||||
mov r4, r1 /* Special optimised code below */
|
||||
mov r5, r3
|
||||
ldmfd r4!, {r0-r3}
|
||||
stmfd sp!, {r0-r3} /* push old task's r3-r0 */
|
||||
stmfd sp!, {r5} /* push old task's psr */
|
||||
mrs r4, spsr
|
||||
stmfd sp!, {r4} /* push old task's spsr */
|
||||
|
||||
ldr r4, =rt_interrupt_from_thread
|
||||
ldr r5, [r4]
|
||||
str sp, [r5] /* store sp in preempted tasks's TCB */
|
||||
|
||||
ldr r6, =rt_interrupt_to_thread
|
||||
ldr r6, [r6]
|
||||
ldr sp, [r6] /* get new task's stack pointer */
|
||||
|
||||
ldmfd sp!, {r4} /* pop new task's spsr */
|
||||
msr SPSR_cxsf, r4
|
||||
ldmfd sp!, {r4} /* pop new task's psr */
|
||||
msr CPSR_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12,lr,pc} /* pop new task's r0-r12,lr & pc */
|
||||
@@ -0,0 +1,499 @@
|
||||
;/*****************************************************************************/
|
||||
;/* SAM7.S: Startup file for Atmel AT91SAM7 device series */
|
||||
;/*****************************************************************************/
|
||||
;/* <<< Use Configuration Wizard in Context Menu >>> */
|
||||
;/*****************************************************************************/
|
||||
;/* This file is part of the uVision/ARM development tools. */
|
||||
;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */
|
||||
;/* This software may only be used under the terms of a valid, current, */
|
||||
;/* end user licence from KEIL for a compatible version of KEIL software */
|
||||
;/* development tools. Nothing else gives you the right to use this software. */
|
||||
;/*****************************************************************************/
|
||||
|
||||
|
||||
;/*
|
||||
; * The SAM7.S code is executed after CPU Reset. This file may be
|
||||
; * translated with the following SET symbols. In uVision these SET
|
||||
; * symbols are entered under Options - ASM - Define.
|
||||
; *
|
||||
; * REMAP: when set the startup code remaps exception vectors from
|
||||
; * on-chip RAM to address 0.
|
||||
; *
|
||||
; * RAM_INTVEC: when set the startup code copies exception vectors
|
||||
; * from on-chip Flash to on-chip RAM.
|
||||
; */
|
||||
|
||||
|
||||
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
|
||||
|
||||
Mode_USR EQU 0x10
|
||||
Mode_FIQ EQU 0x11
|
||||
Mode_IRQ EQU 0x12
|
||||
Mode_SVC EQU 0x13
|
||||
Mode_ABT EQU 0x17
|
||||
Mode_UND EQU 0x1B
|
||||
Mode_SYS EQU 0x1F
|
||||
|
||||
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
|
||||
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
|
||||
|
||||
|
||||
; Internal Memory Base Addresses
|
||||
FLASH_BASE EQU 0x00100000
|
||||
RAM_BASE EQU 0x00200000
|
||||
|
||||
|
||||
;// <h> Stack Configuration (Stack Sizes in Bytes)
|
||||
;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>
|
||||
;// </h>
|
||||
|
||||
UND_Stack_Size EQU 0x00000000
|
||||
SVC_Stack_Size EQU 0x00000100
|
||||
ABT_Stack_Size EQU 0x00000000
|
||||
FIQ_Stack_Size EQU 0x00000000
|
||||
IRQ_Stack_Size EQU 0x00000100
|
||||
USR_Stack_Size EQU 0x00000100
|
||||
|
||||
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
|
||||
FIQ_Stack_Size + IRQ_Stack_Size)
|
||||
|
||||
AREA STACK, NOINIT, READWRITE, ALIGN=3
|
||||
|
||||
Stack_Mem SPACE USR_Stack_Size
|
||||
__initial_sp SPACE ISR_Stack_Size
|
||||
Stack_Top
|
||||
|
||||
|
||||
;// <h> Heap Configuration
|
||||
;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF>
|
||||
;// </h>
|
||||
|
||||
Heap_Size EQU 0x00000000
|
||||
|
||||
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
||||
__heap_base
|
||||
Heap_Mem SPACE Heap_Size
|
||||
__heap_limit
|
||||
|
||||
|
||||
; Reset Controller (RSTC) definitions
|
||||
RSTC_BASE EQU 0xFFFFFD00 ; RSTC Base Address
|
||||
RSTC_MR EQU 0x08 ; RSTC_MR Offset
|
||||
|
||||
;/*
|
||||
;// <e> Reset Controller (RSTC)
|
||||
;// <o1.0> URSTEN: User Reset Enable
|
||||
;// <i> Enables NRST Pin to generate Reset
|
||||
;// <o1.8..11> ERSTL: External Reset Length <0-15>
|
||||
;// <i> External Reset Time in 2^(ERSTL+1) Slow Clock Cycles
|
||||
;// </e>
|
||||
;*/
|
||||
RSTC_SETUP EQU 1
|
||||
RSTC_MR_Val EQU 0xA5000401
|
||||
|
||||
|
||||
; Embedded Flash Controller (EFC) definitions
|
||||
EFC_BASE EQU 0xFFFFFF00 ; EFC Base Address
|
||||
EFC0_FMR EQU 0x60 ; EFC0_FMR Offset
|
||||
EFC1_FMR EQU 0x70 ; EFC1_FMR Offset
|
||||
|
||||
;// <e> Embedded Flash Controller 0 (EFC0)
|
||||
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
|
||||
;// <i> Number of Master Clock Cycles in 1us
|
||||
;// <o1.8..9> FWS: Flash Wait State
|
||||
;// <0=> Read: 1 cycle / Write: 2 cycles
|
||||
;// <1=> Read: 2 cycle / Write: 3 cycles
|
||||
;// <2=> Read: 3 cycle / Write: 4 cycles
|
||||
;// <3=> Read: 4 cycle / Write: 4 cycles
|
||||
;// </e>
|
||||
EFC0_SETUP EQU 1
|
||||
EFC0_FMR_Val EQU 0x00320100
|
||||
|
||||
;// <e> Embedded Flash Controller 1 (EFC1)
|
||||
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
|
||||
;// <i> Number of Master Clock Cycles in 1us
|
||||
;// <o1.8..9> FWS: Flash Wait State
|
||||
;// <0=> Read: 1 cycle / Write: 2 cycles
|
||||
;// <1=> Read: 2 cycle / Write: 3 cycles
|
||||
;// <2=> Read: 3 cycle / Write: 4 cycles
|
||||
;// <3=> Read: 4 cycle / Write: 4 cycles
|
||||
;// </e>
|
||||
EFC1_SETUP EQU 0
|
||||
EFC1_FMR_Val EQU 0x00320100
|
||||
|
||||
|
||||
; Watchdog Timer (WDT) definitions
|
||||
WDT_BASE EQU 0xFFFFFD40 ; WDT Base Address
|
||||
WDT_MR EQU 0x04 ; WDT_MR Offset
|
||||
|
||||
;// <e> Watchdog Timer (WDT)
|
||||
;// <o1.0..11> WDV: Watchdog Counter Value <0-4095>
|
||||
;// <o1.16..27> WDD: Watchdog Delta Value <0-4095>
|
||||
;// <o1.12> WDFIEN: Watchdog Fault Interrupt Enable
|
||||
;// <o1.13> WDRSTEN: Watchdog Reset Enable
|
||||
;// <o1.14> WDRPROC: Watchdog Reset Processor
|
||||
;// <o1.28> WDDBGHLT: Watchdog Debug Halt
|
||||
;// <o1.29> WDIDLEHLT: Watchdog Idle Halt
|
||||
;// <o1.15> WDDIS: Watchdog Disable
|
||||
;// </e>
|
||||
WDT_SETUP EQU 1
|
||||
WDT_MR_Val EQU 0x00008000
|
||||
|
||||
|
||||
; Power Mangement Controller (PMC) definitions
|
||||
PMC_BASE EQU 0xFFFFFC00 ; PMC Base Address
|
||||
PMC_MOR EQU 0x20 ; PMC_MOR Offset
|
||||
PMC_MCFR EQU 0x24 ; PMC_MCFR Offset
|
||||
PMC_PLLR EQU 0x2C ; PMC_PLLR Offset
|
||||
PMC_MCKR EQU 0x30 ; PMC_MCKR Offset
|
||||
PMC_SR EQU 0x68 ; PMC_SR Offset
|
||||
PMC_MOSCEN EQU (1<<0) ; Main Oscillator Enable
|
||||
PMC_OSCBYPASS EQU (1<<1) ; Main Oscillator Bypass
|
||||
PMC_OSCOUNT EQU (0xFF<<8) ; Main OScillator Start-up Time
|
||||
PMC_DIV EQU (0xFF<<0) ; PLL Divider
|
||||
PMC_PLLCOUNT EQU (0x3F<<8) ; PLL Lock Counter
|
||||
PMC_OUT EQU (0x03<<14) ; PLL Clock Frequency Range
|
||||
PMC_MUL EQU (0x7FF<<16) ; PLL Multiplier
|
||||
PMC_USBDIV EQU (0x03<<28) ; USB Clock Divider
|
||||
PMC_CSS EQU (3<<0) ; Clock Source Selection
|
||||
PMC_PRES EQU (7<<2) ; Prescaler Selection
|
||||
PMC_MOSCS EQU (1<<0) ; Main Oscillator Stable
|
||||
PMC_LOCK EQU (1<<2) ; PLL Lock Status
|
||||
PMC_MCKRDY EQU (1<<3) ; Master Clock Status
|
||||
|
||||
;// <e> Power Mangement Controller (PMC)
|
||||
;// <h> Main Oscillator
|
||||
;// <o1.0> MOSCEN: Main Oscillator Enable
|
||||
;// <o1.1> OSCBYPASS: Oscillator Bypass
|
||||
;// <o1.8..15> OSCCOUNT: Main Oscillator Startup Time <0-255>
|
||||
;// </h>
|
||||
;// <h> Phase Locked Loop (PLL)
|
||||
;// <o2.0..7> DIV: PLL Divider <0-255>
|
||||
;// <o2.16..26> MUL: PLL Multiplier <0-2047>
|
||||
;// <i> PLL Output is multiplied by MUL+1
|
||||
;// <o2.14..15> OUT: PLL Clock Frequency Range
|
||||
;// <0=> 80..160MHz <1=> Reserved
|
||||
;// <2=> 150..220MHz <3=> Reserved
|
||||
;// <o2.8..13> PLLCOUNT: PLL Lock Counter <0-63>
|
||||
;// <o2.28..29> USBDIV: USB Clock Divider
|
||||
;// <0=> None <1=> 2 <2=> 4 <3=> Reserved
|
||||
;// </h>
|
||||
;// <o3.0..1> CSS: Clock Source Selection
|
||||
;// <0=> Slow Clock
|
||||
;// <1=> Main Clock
|
||||
;// <2=> Reserved
|
||||
;// <3=> PLL Clock
|
||||
;// <o3.2..4> PRES: Prescaler
|
||||
;// <0=> None
|
||||
;// <1=> Clock / 2 <2=> Clock / 4
|
||||
;// <3=> Clock / 8 <4=> Clock / 16
|
||||
;// <5=> Clock / 32 <6=> Clock / 64
|
||||
;// <7=> Reserved
|
||||
;// </e>
|
||||
PMC_SETUP EQU 1
|
||||
PMC_MOR_Val EQU 0x00000601
|
||||
PMC_PLLR_Val EQU 0x00191C05
|
||||
PMC_MCKR_Val EQU 0x00000007
|
||||
|
||||
|
||||
PRESERVE8
|
||||
|
||||
|
||||
; Area Definition and Entry Point
|
||||
; Startup Code must be linked first at Address at which it expects to run.
|
||||
|
||||
AREA RESET, CODE, READONLY
|
||||
ARM
|
||||
|
||||
|
||||
; Exception Vectors
|
||||
; Mapped to Address 0.
|
||||
; Absolute addressing mode must be used.
|
||||
; Dummy Handlers are implemented as infinite loops which can be modified.
|
||||
|
||||
Vectors LDR PC,Reset_Addr
|
||||
LDR PC,Undef_Addr
|
||||
LDR PC,SWI_Addr
|
||||
LDR PC,PAbt_Addr
|
||||
LDR PC,DAbt_Addr
|
||||
NOP ; Reserved Vector
|
||||
LDR PC,IRQ_Addr
|
||||
LDR PC,FIQ_Addr
|
||||
|
||||
Reset_Addr DCD Reset_Handler
|
||||
Undef_Addr DCD Undef_Handler
|
||||
SWI_Addr DCD SWI_Handler
|
||||
PAbt_Addr DCD PAbt_Handler
|
||||
DAbt_Addr DCD DAbt_Handler
|
||||
DCD 0 ; Reserved Address
|
||||
IRQ_Addr DCD IRQ_Handler
|
||||
FIQ_Addr DCD FIQ_Handler
|
||||
|
||||
Undef_Handler B Undef_Handler
|
||||
SWI_Handler B SWI_Handler
|
||||
PAbt_Handler B PAbt_Handler
|
||||
DAbt_Handler B DAbt_Handler
|
||||
FIQ_Handler B FIQ_Handler
|
||||
|
||||
|
||||
; Reset Handler
|
||||
|
||||
EXPORT Reset_Handler
|
||||
Reset_Handler
|
||||
|
||||
|
||||
; Setup RSTC
|
||||
IF RSTC_SETUP != 0
|
||||
LDR R0, =RSTC_BASE
|
||||
LDR R1, =RSTC_MR_Val
|
||||
STR R1, [R0, #RSTC_MR]
|
||||
ENDIF
|
||||
|
||||
|
||||
; Setup EFC0
|
||||
IF EFC0_SETUP != 0
|
||||
LDR R0, =EFC_BASE
|
||||
LDR R1, =EFC0_FMR_Val
|
||||
STR R1, [R0, #EFC0_FMR]
|
||||
ENDIF
|
||||
|
||||
; Setup EFC1
|
||||
IF EFC1_SETUP != 0
|
||||
LDR R0, =EFC_BASE
|
||||
LDR R1, =EFC1_FMR_Val
|
||||
STR R1, [R0, #EFC1_FMR]
|
||||
ENDIF
|
||||
|
||||
; Setup WDT
|
||||
IF WDT_SETUP != 0
|
||||
LDR R0, =WDT_BASE
|
||||
LDR R1, =WDT_MR_Val
|
||||
STR R1, [R0, #WDT_MR]
|
||||
ENDIF
|
||||
|
||||
|
||||
; Setup PMC
|
||||
IF PMC_SETUP != 0
|
||||
LDR R0, =PMC_BASE
|
||||
|
||||
; Setup Main Oscillator
|
||||
LDR R1, =PMC_MOR_Val
|
||||
STR R1, [R0, #PMC_MOR]
|
||||
|
||||
; Wait until Main Oscillator is stablilized
|
||||
IF (PMC_MOR_Val:AND:PMC_MOSCEN) != 0
|
||||
MOSCS_Loop LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MOSCS
|
||||
BEQ MOSCS_Loop
|
||||
ENDIF
|
||||
|
||||
; Setup the PLL
|
||||
IF (PMC_PLLR_Val:AND:PMC_MUL) != 0
|
||||
LDR R1, =PMC_PLLR_Val
|
||||
STR R1, [R0, #PMC_PLLR]
|
||||
|
||||
; Wait until PLL is stabilized
|
||||
PLL_Loop LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_LOCK
|
||||
BEQ PLL_Loop
|
||||
ENDIF
|
||||
|
||||
; Select Clock
|
||||
IF (PMC_MCKR_Val:AND:PMC_CSS) == 1 ; Main Clock Selected
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
AND R1, #PMC_CSS
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy1
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy2
|
||||
ELIF (PMC_MCKR_Val:AND:PMC_CSS) == 3 ; PLL Clock Selected
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
AND R1, #PMC_PRES
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy1
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy2
|
||||
ENDIF ; Select Clock
|
||||
ENDIF ; PMC_SETUP
|
||||
|
||||
|
||||
; Copy Exception Vectors to Internal RAM
|
||||
|
||||
IF :DEF:RAM_INTVEC
|
||||
ADR R8, Vectors ; Source
|
||||
LDR R9, =RAM_BASE ; Destination
|
||||
LDMIA R8!, {R0-R7} ; Load Vectors
|
||||
STMIA R9!, {R0-R7} ; Store Vectors
|
||||
LDMIA R8!, {R0-R7} ; Load Handler Addresses
|
||||
STMIA R9!, {R0-R7} ; Store Handler Addresses
|
||||
ENDIF
|
||||
|
||||
|
||||
; Remap on-chip RAM to address 0
|
||||
|
||||
MC_BASE EQU 0xFFFFFF00 ; MC Base Address
|
||||
MC_RCR EQU 0x00 ; MC_RCR Offset
|
||||
|
||||
IF :DEF:REMAP
|
||||
LDR R0, =MC_BASE
|
||||
MOV R1, #1
|
||||
STR R1, [R0, #MC_RCR] ; Remap
|
||||
ENDIF
|
||||
|
||||
|
||||
; Setup Stack for each mode
|
||||
|
||||
LDR R0, =Stack_Top
|
||||
|
||||
; Enter Undefined Instruction Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
SUB R0, R0, #UND_Stack_Size
|
||||
|
||||
; Enter Abort Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
SUB R0, R0, #ABT_Stack_Size
|
||||
|
||||
; Enter FIQ Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
SUB R0, R0, #FIQ_Stack_Size
|
||||
|
||||
; Enter IRQ Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
SUB R0, R0, #IRQ_Stack_Size
|
||||
|
||||
; Enter Supervisor Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
SUB R0, R0, #SVC_Stack_Size
|
||||
|
||||
; Enter User Mode and set its Stack Pointer
|
||||
; MSR CPSR_c, #Mode_USR
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __initial_sp
|
||||
|
||||
ELSE
|
||||
|
||||
; No usr mode stack here.
|
||||
;MOV SP, R0
|
||||
;SUB SL, SP, #USR_Stack_Size
|
||||
|
||||
ENDIF
|
||||
|
||||
|
||||
; Enter the C code
|
||||
|
||||
IMPORT __main
|
||||
LDR R0, =__main
|
||||
BX R0
|
||||
|
||||
IMPORT rt_interrupt_enter
|
||||
IMPORT rt_interrupt_leave
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
IMPORT rt_hw_trap_irq
|
||||
|
||||
IRQ_Handler PROC
|
||||
EXPORT IRQ_Handler
|
||||
STMFD sp!, {r0-r12,lr}
|
||||
BL rt_interrupt_enter
|
||||
BL rt_hw_trap_irq
|
||||
BL rt_interrupt_leave
|
||||
|
||||
; if rt_thread_switch_interrupt_flag set, jump to
|
||||
; rt_hw_context_switch_interrupt_do and don't return
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #1
|
||||
BEQ rt_hw_context_switch_interrupt_do
|
||||
|
||||
LDMFD sp!, {r0-r12,lr}
|
||||
SUBS pc, lr, #4
|
||||
ENDP
|
||||
|
||||
; /*
|
||||
; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
|
||||
; */
|
||||
rt_hw_context_switch_interrupt_do PROC
|
||||
EXPORT rt_hw_context_switch_interrupt_do
|
||||
MOV r1, #0 ; clear flag
|
||||
STR r1, [r0]
|
||||
|
||||
LDMFD sp!, {r0-r12,lr}; reload saved registers
|
||||
STMFD sp!, {r0-r3} ; save r0-r3
|
||||
MOV r1, sp
|
||||
ADD sp, sp, #16 ; restore sp
|
||||
SUB r2, lr, #4 ; save old task's pc to r2
|
||||
|
||||
MRS r3, spsr ; get cpsr of interrupt thread
|
||||
|
||||
; switch to SVC mode and no interrupt
|
||||
MSR cpsr_c, #I_Bit|F_Bit|Mode_SVC
|
||||
|
||||
STMFD sp!, {r2} ; push old task's pc
|
||||
STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4
|
||||
MOV r4, r1 ; Special optimised code below
|
||||
MOV r5, r3
|
||||
LDMFD r4!, {r0-r3}
|
||||
STMFD sp!, {r0-r3} ; push old task's r3-r0
|
||||
STMFD sp!, {r5} ; push old task's cpsr
|
||||
MRS r4, spsr
|
||||
STMFD sp!, {r4} ; push old task's spsr
|
||||
|
||||
LDR r4, =rt_interrupt_from_thread
|
||||
LDR r5, [r4]
|
||||
STR sp, [r5] ; store sp in preempted tasks's TCB
|
||||
|
||||
LDR r6, =rt_interrupt_to_thread
|
||||
LDR r6, [r6]
|
||||
LDR sp, [r6] ; get new task's stack pointer
|
||||
|
||||
LDMFD sp!, {r4} ; pop new task's spsr
|
||||
MSR spsr_cxsf, r4
|
||||
LDMFD sp!, {r4} ; pop new task's psr
|
||||
MSR cpsr_cxsf, r4
|
||||
|
||||
LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
|
||||
ENDP
|
||||
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __heap_base
|
||||
EXPORT __heap_limit
|
||||
|
||||
ELSE
|
||||
; User Initial Stack & Heap
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
EXPORT __user_initial_stackheap
|
||||
__user_initial_stackheap
|
||||
|
||||
LDR R0, = Heap_Mem
|
||||
LDR R1, = (Stack_Mem + IRQ_Stack_Size)
|
||||
LDR R2, = (Heap_Mem + Heap_Size)
|
||||
LDR R3, = Stack_Mem
|
||||
BX LR
|
||||
ENDIF
|
||||
|
||||
END
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-25 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#include "AT91SAM7S.h"
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
void rt_hw_trap_irq()
|
||||
{
|
||||
rt_isr_handler_t hander = (rt_isr_handler_t)AT91C_AIC_IVR;
|
||||
|
||||
hander(AT91C_AIC_ISR);
|
||||
|
||||
/* end of interrupt */
|
||||
AT91C_AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq()
|
||||
{
|
||||
rt_kprintf("fast interrupt request\n");
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-03-13 Bernard first version
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \addtogroup xgs3c4510
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
#define NOINT 0xc0
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
mrs r0, cpsr
|
||||
orr r1, r0, #NOINT
|
||||
msr cpsr_c, r1
|
||||
mov pc, lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
msr cpsr, r0
|
||||
mov pc, lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
|
||||
stmfd sp!, {r0-r12, lr} @ push lr & register file
|
||||
|
||||
mrs r4, cpsr
|
||||
stmfd sp!, {r4} @ push cpsr
|
||||
mrs r4, spsr
|
||||
stmfd sp!, {r4} @ push spsr
|
||||
|
||||
str sp, [r0] @ store sp in preempted tasks TCB
|
||||
ldr sp, [r1] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r4} @ pop new task cpsr
|
||||
msr cpsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
ldr sp, [r0] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r4} @ pop new task cpsr
|
||||
msr cpsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
str r3, [r2]
|
||||
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
str r0, [r2]
|
||||
_reswitch:
|
||||
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
mov pc, lr
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-01-20 Bernard first version
|
||||
*/
|
||||
|
||||
NOINT EQU 0xc0 ; disable interrupt in psr
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
ARM
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, cpsr
|
||||
ORR r1, r0, #NOINT
|
||||
MSR cpsr_c, r1
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR cpsr_c, r0
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC)
|
||||
STMFD sp!, {r0-r12, lr} ; push lr & register file
|
||||
|
||||
MRS r4, cpsr
|
||||
STMFD sp!, {r4} ; push cpsr
|
||||
MRS r4, spsr
|
||||
STMFD sp!, {r4} ; push spsr
|
||||
|
||||
STR sp, [r0] ; store sp in preempted tasks TCB
|
||||
LDR sp, [r1] ; get new task stack pointer
|
||||
|
||||
LDMFD sp!, {r4} ; pop new task spsr
|
||||
MSR spsr_cxsf, r4
|
||||
LDMFD sp!, {r4} ; pop new task cpsr
|
||||
MSR cpsr_cxsf, r4
|
||||
|
||||
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
LDR sp, [r0] ; get new task stack pointer
|
||||
|
||||
LDMFD sp!, {r4} ; pop new task spsr
|
||||
MSR spsr_cxsf, r4
|
||||
LDMFD sp!, {r4} ; pop new task cpsr
|
||||
MSR cpsr_cxsf, r4
|
||||
|
||||
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
; */
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
rt_hw_context_switch_interrupt PROC
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1
|
||||
STR r3, [r2]
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
END
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7X
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* this function will reset CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard first version
|
||||
* 2013-03-29 aozima Modify the interrupt interface implementations.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include "AT91SAM7X256.h"
|
||||
|
||||
#define MAX_HANDLERS 32
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
struct rt_irq_desc irq_desc[MAX_HANDLERS];
|
||||
|
||||
extern rt_uint32_t rt_interrupt_nest;
|
||||
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
static void rt_hw_interrupt_handler(int vector, void *param)
|
||||
{
|
||||
rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
rt_base_t index;
|
||||
|
||||
/* init exceptions table */
|
||||
for(index=0; index < MAX_HANDLERS; index++)
|
||||
{
|
||||
irq_desc[index].handler = (rt_isr_handler_t)rt_hw_interrupt_handler;
|
||||
irq_desc[index].param = RT_NULL;
|
||||
}
|
||||
|
||||
for (index = 0; index < MAX_HANDLERS; index ++)
|
||||
{
|
||||
AT91C_BASE_AIC->AIC_SVR[index] = (rt_uint32_t)rt_hw_interrupt_handler;
|
||||
}
|
||||
|
||||
/* init interrupt nest, and context in thread sp */
|
||||
rt_interrupt_nest = 0;
|
||||
rt_interrupt_from_thread = 0;
|
||||
rt_interrupt_to_thread = 0;
|
||||
rt_thread_switch_interrupt_flag = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_mask(int vector)
|
||||
{
|
||||
/* disable interrupt */
|
||||
AT91C_BASE_AIC->AIC_IDCR = 1 << vector;
|
||||
|
||||
/* clear interrupt */
|
||||
AT91C_BASE_AIC->AIC_ICCR = 1 << vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will un-mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
AT91C_BASE_AIC->AIC_IECR = 1 << vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param handler the interrupt service routine to be installed
|
||||
* @param param the parameter for interrupt service routine
|
||||
* @name unused.
|
||||
*
|
||||
* @return the old handler
|
||||
*/
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name)
|
||||
{
|
||||
rt_isr_handler_t old_handler = RT_NULL;
|
||||
if(vector >= 0 && vector < MAX_HANDLERS)
|
||||
{
|
||||
old_handler = irq_desc[vector].handler;
|
||||
if (handler != RT_NULL)
|
||||
{
|
||||
irq_desc[vector].handler = (rt_isr_handler_t)handler;
|
||||
irq_desc[vector].param = param;
|
||||
}
|
||||
}
|
||||
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-23 Bernard the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
#define SVCMODE 0x13
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
*(--stk) = SVCMODE; /* cpsr */
|
||||
*(--stk) = SVCMODE; /* spsr */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-31 Bernard first version
|
||||
*/
|
||||
|
||||
/* Internal Memory Base Addresses */
|
||||
.equ FLASH_BASE, 0x00100000
|
||||
.equ RAM_BASE, 0x00200000
|
||||
|
||||
/* Stack Configuration */
|
||||
.equ TOP_STACK, 0x00204000
|
||||
.equ UND_STACK_SIZE, 0x00000100
|
||||
.equ SVC_STACK_SIZE, 0x00000400
|
||||
.equ ABT_STACK_SIZE, 0x00000100
|
||||
.equ FIQ_STACK_SIZE, 0x00000100
|
||||
.equ IRQ_STACK_SIZE, 0x00000100
|
||||
.equ USR_STACK_SIZE, 0x00000004
|
||||
|
||||
/* ARM architecture definitions */
|
||||
.equ MODE_USR, 0x10
|
||||
.equ MODE_FIQ, 0x11
|
||||
.equ MODE_IRQ, 0x12
|
||||
.equ MODE_SVC, 0x13
|
||||
.equ MODE_ABT, 0x17
|
||||
.equ MODE_UND, 0x1B
|
||||
.equ MODE_SYS, 0x1F
|
||||
|
||||
.equ I_BIT, 0x80 /* when this bit is set, IRQ is disabled */
|
||||
.equ F_BIT, 0x40 /* when this bit is set, FIQ is disabled */
|
||||
|
||||
.section .init, "ax"
|
||||
.code 32
|
||||
.align 0
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
ldr pc, _vector_undef
|
||||
ldr pc, _vector_swi
|
||||
ldr pc, _vector_pabt
|
||||
ldr pc, _vector_dabt
|
||||
nop /* reserved vector */
|
||||
ldr pc, _vector_irq
|
||||
ldr pc, _vector_fiq
|
||||
|
||||
_vector_undef: .word vector_undef
|
||||
_vector_swi: .word vector_swi
|
||||
_vector_pabt: .word vector_pabt
|
||||
_vector_dabt: .word vector_dabt
|
||||
_vector_resv: .word vector_resv
|
||||
_vector_irq: .word vector_irq
|
||||
_vector_fiq: .word vector_fiq
|
||||
|
||||
/*
|
||||
* rtthread bss start and end
|
||||
* which are defined in linker script
|
||||
*/
|
||||
.globl _bss_start
|
||||
_bss_start: .word __bss_start
|
||||
.globl _bss_end
|
||||
_bss_end: .word __bss_end
|
||||
|
||||
/* the system entry */
|
||||
reset:
|
||||
/* disable watchdog */
|
||||
ldr r0, =0xFFFFFD40
|
||||
ldr r1, =0x00008000
|
||||
str r1, [r0, #0x04]
|
||||
|
||||
/* enable the main oscillator */
|
||||
ldr r0, =0xFFFFFC00
|
||||
ldr r1, =0x00000601
|
||||
str r1, [r0, #0x20]
|
||||
|
||||
/* wait for main oscillator to stabilize */
|
||||
moscs_loop:
|
||||
ldr r2, [r0, #0x68]
|
||||
ands r2, r2, #1
|
||||
beq moscs_loop
|
||||
|
||||
/* set up the PLL */
|
||||
ldr r1, =0x00191C05
|
||||
str r1, [r0, #0x2C]
|
||||
|
||||
/* wait for PLL to lock */
|
||||
pll_loop:
|
||||
ldr r2, [r0, #0x68]
|
||||
ands r2, r2, #0x04
|
||||
beq pll_loop
|
||||
|
||||
/* select clock */
|
||||
ldr r1, =0x00000007
|
||||
str r1, [r0, #0x30]
|
||||
|
||||
#ifdef __FLASH_BUILD__
|
||||
/* copy exception vectors into internal sram */
|
||||
/*
|
||||
mov r8, #RAM_BASE
|
||||
ldr r9, =_start
|
||||
ldmia r9!, {r0-r7}
|
||||
stmia r8!, {r0-r7}
|
||||
ldmia r9!, {r0-r6}
|
||||
stmia r8!, {r0-r6}
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* setup stack for each mode */
|
||||
ldr r0, =TOP_STACK
|
||||
|
||||
/* set stack */
|
||||
/* undefined instruction mode */
|
||||
msr cpsr_c, #MODE_UND|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #UND_STACK_SIZE
|
||||
|
||||
/* abort mode */
|
||||
msr cpsr_c, #MODE_ABT|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #ABT_STACK_SIZE
|
||||
|
||||
/* FIQ mode */
|
||||
msr cpsr_c, #MODE_FIQ|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #FIQ_STACK_SIZE
|
||||
|
||||
/* IRQ mode */
|
||||
msr cpsr_c, #MODE_IRQ|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
sub r0, r0, #IRQ_STACK_SIZE
|
||||
|
||||
/* supervisor mode */
|
||||
msr cpsr_c, #MODE_SVC|I_BIT|F_BIT
|
||||
mov sp, r0
|
||||
|
||||
/* remap SRAM to 0x0000 */
|
||||
/*
|
||||
ldr r0, =0xFFFFFF00
|
||||
mov r1, #0x01
|
||||
str r1, [r0]
|
||||
*/
|
||||
|
||||
/* mask all IRQs */
|
||||
ldr r1, =0xFFFFF124
|
||||
ldr r0, =0XFFFFFFFF
|
||||
str r0, [r1]
|
||||
|
||||
/* copy .data to SRAM */
|
||||
ldr r1, =_sidata /* .data start in image */
|
||||
ldr r2, =_edata /* .data end in image */
|
||||
ldr r3, =_sdata /* sram data start */
|
||||
data_loop:
|
||||
ldr r0, [r1, #0]
|
||||
str r0, [r3]
|
||||
|
||||
add r1, r1, #4
|
||||
add r3, r3, #4
|
||||
|
||||
cmp r3, r2 /* check if data to clear */
|
||||
blo data_loop /* loop until done */
|
||||
|
||||
/* clear .bss */
|
||||
mov r0,#0 /* get a zero */
|
||||
ldr r1,=__bss_start /* bss start */
|
||||
ldr r2,=__bss_end /* bss end */
|
||||
|
||||
bss_loop:
|
||||
cmp r1,r2 /* check if data to clear */
|
||||
strlo r0,[r1],#4 /* clear 4 bytes */
|
||||
blo bss_loop /* loop until done */
|
||||
|
||||
/* call C++ constructors of global objects */
|
||||
ldr r0, =__ctors_start__
|
||||
ldr r1, =__ctors_end__
|
||||
|
||||
ctor_loop:
|
||||
cmp r0, r1
|
||||
beq ctor_end
|
||||
ldr r2, [r0], #4
|
||||
stmfd sp!, {r0-r1}
|
||||
mov lr, pc
|
||||
bx r2
|
||||
ldmfd sp!, {r0-r1}
|
||||
b ctor_loop
|
||||
ctor_end:
|
||||
|
||||
|
||||
/* start RT-Thread Kernel */
|
||||
ldr pc, _rtthread_startup
|
||||
|
||||
_rtthread_startup: .word rtthread_startup
|
||||
|
||||
/* exception handlers */
|
||||
vector_undef: b vector_undef
|
||||
vector_swi : b vector_swi
|
||||
vector_pabt : b vector_pabt
|
||||
vector_dabt : b vector_dabt
|
||||
vector_resv : b vector_resv
|
||||
|
||||
.globl rt_interrupt_enter
|
||||
.globl rt_interrupt_leave
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
vector_irq:
|
||||
stmfd sp!, {r0-r12,lr}
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
/*
|
||||
* if rt_thread_switch_interrupt_flag set, jump to
|
||||
* rt_hw_context_switch_interrupt_do and don't return
|
||||
*/
|
||||
ldr r0, =rt_thread_switch_interrupt_flag
|
||||
ldr r1, [r0]
|
||||
cmp r1, #1
|
||||
beq rt_hw_context_switch_interrupt_do
|
||||
|
||||
ldmfd sp!, {r0-r12,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
vector_fiq:
|
||||
stmfd sp!,{r0-r7,lr}
|
||||
bl rt_hw_trap_fiq
|
||||
ldmfd sp!,{r0-r7,lr}
|
||||
subs pc,lr,#4
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt_do(rt_base_t flag)
|
||||
*/
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
mov r1, #0 @ clear flag
|
||||
str r1, [r0]
|
||||
|
||||
ldmfd sp!, {r0-r12,lr}@ reload saved registers
|
||||
stmfd sp!, {r0-r3} @ save r0-r3
|
||||
mov r1, sp
|
||||
add sp, sp, #16 @ restore sp
|
||||
sub r2, lr, #4 @ save old task's pc to r2
|
||||
|
||||
mrs r3, spsr @ disable interrupt
|
||||
orr r0, r3, #I_BIT|F_BIT
|
||||
msr spsr_c, r0
|
||||
|
||||
ldr r0, =.+8 @ switch to interrupted task's stack
|
||||
movs pc, r0
|
||||
|
||||
stmfd sp!, {r2} @ push old task's pc
|
||||
stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4
|
||||
mov r4, r1 @ Special optimised code below
|
||||
mov r5, r3
|
||||
ldmfd r4!, {r0-r3}
|
||||
stmfd sp!, {r0-r3} @ push old task's r3-r0
|
||||
stmfd sp!, {r5} @ push old task's psr
|
||||
mrs r4, spsr
|
||||
stmfd sp!, {r4} @ push old task's spsr
|
||||
|
||||
ldr r4, =rt_interrupt_from_thread
|
||||
ldr r5, [r4]
|
||||
str sp, [r5] @ store sp in preempted tasks's TCB
|
||||
|
||||
ldr r6, =rt_interrupt_to_thread
|
||||
ldr r6, [r6]
|
||||
ldr sp, [r6] @ get new task's stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task's spsr
|
||||
msr SPSR_cxsf, r4
|
||||
ldmfd sp!, {r4} @ pop new task's psr
|
||||
msr CPSR_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12,lr,pc} @ pop new task's r0-r12,lr & pc
|
||||
@@ -0,0 +1,517 @@
|
||||
;/*****************************************************************************/
|
||||
;/* SAM7.S: Startup file for Atmel AT91SAM7 device series */
|
||||
;/*****************************************************************************/
|
||||
;/* <<< Use Configuration Wizard in Context Menu >>> */
|
||||
;/*****************************************************************************/
|
||||
;/* This file is part of the uVision/ARM development tools. */
|
||||
;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */
|
||||
;/* This software may only be used under the terms of a valid, current, */
|
||||
;/* end user licence from KEIL for a compatible version of KEIL software */
|
||||
;/* development tools. Nothing else gives you the right to use this software. */
|
||||
;/*****************************************************************************/
|
||||
|
||||
|
||||
;/*
|
||||
; * The SAM7.S code is executed after CPU Reset. This file may be
|
||||
; * translated with the following SET symbols. In uVision these SET
|
||||
; * symbols are entered under Options - ASM - Define.
|
||||
; *
|
||||
; * REMAP: when set the startup code remaps exception vectors from
|
||||
; * on-chip RAM to address 0.
|
||||
; *
|
||||
; * RAM_INTVEC: when set the startup code copies exception vectors
|
||||
; * from on-chip Flash to on-chip RAM.
|
||||
; */
|
||||
|
||||
|
||||
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
|
||||
|
||||
; 2009-12-28 MingBai Bug fix (USR mode stack removed).
|
||||
; 2009-12-29 MingBai Merge svc and irq stack, add abort handler.
|
||||
|
||||
Mode_USR EQU 0x10
|
||||
Mode_FIQ EQU 0x11
|
||||
Mode_IRQ EQU 0x12
|
||||
Mode_SVC EQU 0x13
|
||||
Mode_ABT EQU 0x17
|
||||
Mode_UND EQU 0x1B
|
||||
Mode_SYS EQU 0x1F
|
||||
|
||||
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
|
||||
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
|
||||
|
||||
|
||||
; Internal Memory Base Addresses
|
||||
FLASH_BASE EQU 0x00100000
|
||||
RAM_BASE EQU 0x00200000
|
||||
|
||||
|
||||
;// <h> Stack Configuration (Stack Sizes in Bytes)
|
||||
;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>
|
||||
;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>
|
||||
;// </h>
|
||||
|
||||
UND_Stack_Size EQU 0x00000000
|
||||
SVC_Stack_Size EQU 0x00000000
|
||||
ABT_Stack_Size EQU 0x00000000
|
||||
FIQ_Stack_Size EQU 0x00000000
|
||||
IRQ_Stack_Size EQU 0x00000100
|
||||
USR_Stack_Size EQU 0x00000000
|
||||
|
||||
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
|
||||
FIQ_Stack_Size + IRQ_Stack_Size)
|
||||
|
||||
AREA STACK, NOINIT, READWRITE, ALIGN=3
|
||||
|
||||
Stack_Mem SPACE USR_Stack_Size
|
||||
__initial_sp SPACE ISR_Stack_Size
|
||||
Stack_Top
|
||||
|
||||
|
||||
;// <h> Heap Configuration
|
||||
;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF>
|
||||
;// </h>
|
||||
|
||||
Heap_Size EQU 0x00000000
|
||||
|
||||
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
||||
__heap_base
|
||||
Heap_Mem SPACE Heap_Size
|
||||
__heap_limit
|
||||
|
||||
|
||||
; Reset Controller (RSTC) definitions
|
||||
RSTC_BASE EQU 0xFFFFFD00 ; RSTC Base Address
|
||||
RSTC_MR EQU 0x08 ; RSTC_MR Offset
|
||||
|
||||
;/*
|
||||
;// <e> Reset Controller (RSTC)
|
||||
;// <o1.0> URSTEN: User Reset Enable
|
||||
;// <i> Enables NRST Pin to generate Reset
|
||||
;// <o1.8..11> ERSTL: External Reset Length <0-15>
|
||||
;// <i> External Reset Time in 2^(ERSTL+1) Slow Clock Cycles
|
||||
;// </e>
|
||||
;*/
|
||||
RSTC_SETUP EQU 1
|
||||
RSTC_MR_Val EQU 0xA5000401
|
||||
|
||||
|
||||
; Embedded Flash Controller (EFC) definitions
|
||||
EFC_BASE EQU 0xFFFFFF00 ; EFC Base Address
|
||||
EFC0_FMR EQU 0x60 ; EFC0_FMR Offset
|
||||
EFC1_FMR EQU 0x70 ; EFC1_FMR Offset
|
||||
|
||||
;// <e> Embedded Flash Controller 0 (EFC0)
|
||||
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
|
||||
;// <i> Number of Master Clock Cycles in 1us
|
||||
;// <o1.8..9> FWS: Flash Wait State
|
||||
;// <0=> Read: 1 cycle / Write: 2 cycles
|
||||
;// <1=> Read: 2 cycle / Write: 3 cycles
|
||||
;// <2=> Read: 3 cycle / Write: 4 cycles
|
||||
;// <3=> Read: 4 cycle / Write: 4 cycles
|
||||
;// </e>
|
||||
EFC0_SETUP EQU 1
|
||||
EFC0_FMR_Val EQU 0x00320100
|
||||
|
||||
;// <e> Embedded Flash Controller 1 (EFC1)
|
||||
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
|
||||
;// <i> Number of Master Clock Cycles in 1us
|
||||
;// <o1.8..9> FWS: Flash Wait State
|
||||
;// <0=> Read: 1 cycle / Write: 2 cycles
|
||||
;// <1=> Read: 2 cycle / Write: 3 cycles
|
||||
;// <2=> Read: 3 cycle / Write: 4 cycles
|
||||
;// <3=> Read: 4 cycle / Write: 4 cycles
|
||||
;// </e>
|
||||
EFC1_SETUP EQU 0
|
||||
EFC1_FMR_Val EQU 0x00320100
|
||||
|
||||
|
||||
; Watchdog Timer (WDT) definitions
|
||||
WDT_BASE EQU 0xFFFFFD40 ; WDT Base Address
|
||||
WDT_MR EQU 0x04 ; WDT_MR Offset
|
||||
|
||||
;// <e> Watchdog Timer (WDT)
|
||||
;// <o1.0..11> WDV: Watchdog Counter Value <0-4095>
|
||||
;// <o1.16..27> WDD: Watchdog Delta Value <0-4095>
|
||||
;// <o1.12> WDFIEN: Watchdog Fault Interrupt Enable
|
||||
;// <o1.13> WDRSTEN: Watchdog Reset Enable
|
||||
;// <o1.14> WDRPROC: Watchdog Reset Processor
|
||||
;// <o1.28> WDDBGHLT: Watchdog Debug Halt
|
||||
;// <o1.29> WDIDLEHLT: Watchdog Idle Halt
|
||||
;// <o1.15> WDDIS: Watchdog Disable
|
||||
;// </e>
|
||||
WDT_SETUP EQU 1
|
||||
WDT_MR_Val EQU 0x00008000
|
||||
|
||||
|
||||
; Power Mangement Controller (PMC) definitions
|
||||
PMC_BASE EQU 0xFFFFFC00 ; PMC Base Address
|
||||
PMC_MOR EQU 0x20 ; PMC_MOR Offset
|
||||
PMC_MCFR EQU 0x24 ; PMC_MCFR Offset
|
||||
PMC_PLLR EQU 0x2C ; PMC_PLLR Offset
|
||||
PMC_MCKR EQU 0x30 ; PMC_MCKR Offset
|
||||
PMC_SR EQU 0x68 ; PMC_SR Offset
|
||||
PMC_MOSCEN EQU (1<<0) ; Main Oscillator Enable
|
||||
PMC_OSCBYPASS EQU (1<<1) ; Main Oscillator Bypass
|
||||
PMC_OSCOUNT EQU (0xFF<<8) ; Main OScillator Start-up Time
|
||||
PMC_DIV EQU (0xFF<<0) ; PLL Divider
|
||||
PMC_PLLCOUNT EQU (0x3F<<8) ; PLL Lock Counter
|
||||
PMC_OUT EQU (0x03<<14) ; PLL Clock Frequency Range
|
||||
PMC_MUL EQU (0x7FF<<16) ; PLL Multiplier
|
||||
PMC_USBDIV EQU (0x03<<28) ; USB Clock Divider
|
||||
PMC_CSS EQU (3<<0) ; Clock Source Selection
|
||||
PMC_PRES EQU (7<<2) ; Prescaler Selection
|
||||
PMC_MOSCS EQU (1<<0) ; Main Oscillator Stable
|
||||
PMC_LOCK EQU (1<<2) ; PLL Lock Status
|
||||
PMC_MCKRDY EQU (1<<3) ; Master Clock Status
|
||||
|
||||
;// <e> Power Mangement Controller (PMC)
|
||||
;// <h> Main Oscillator
|
||||
;// <o1.0> MOSCEN: Main Oscillator Enable
|
||||
;// <o1.1> OSCBYPASS: Oscillator Bypass
|
||||
;// <o1.8..15> OSCCOUNT: Main Oscillator Startup Time <0-255>
|
||||
;// </h>
|
||||
;// <h> Phase Locked Loop (PLL)
|
||||
;// <o2.0..7> DIV: PLL Divider <0-255>
|
||||
;// <o2.16..26> MUL: PLL Multiplier <0-2047>
|
||||
;// <i> PLL Output is multiplied by MUL+1
|
||||
;// <o2.14..15> OUT: PLL Clock Frequency Range
|
||||
;// <0=> 80..160MHz <1=> Reserved
|
||||
;// <2=> 150..220MHz <3=> Reserved
|
||||
;// <o2.8..13> PLLCOUNT: PLL Lock Counter <0-63>
|
||||
;// <o2.28..29> USBDIV: USB Clock Divider
|
||||
;// <0=> None <1=> 2 <2=> 4 <3=> Reserved
|
||||
;// </h>
|
||||
;// <o3.0..1> CSS: Clock Source Selection
|
||||
;// <0=> Slow Clock
|
||||
;// <1=> Main Clock
|
||||
;// <2=> Reserved
|
||||
;// <3=> PLL Clock
|
||||
;// <o3.2..4> PRES: Prescaler
|
||||
;// <0=> None
|
||||
;// <1=> Clock / 2 <2=> Clock / 4
|
||||
;// <3=> Clock / 8 <4=> Clock / 16
|
||||
;// <5=> Clock / 32 <6=> Clock / 64
|
||||
;// <7=> Reserved
|
||||
;// </e>
|
||||
PMC_SETUP EQU 1
|
||||
PMC_MOR_Val EQU 0x00000601
|
||||
PMC_PLLR_Val EQU 0x00191C05
|
||||
PMC_MCKR_Val EQU 0x00000007
|
||||
|
||||
|
||||
PRESERVE8
|
||||
|
||||
|
||||
; Area Definition and Entry Point
|
||||
; Startup Code must be linked first at Address at which it expects to run.
|
||||
|
||||
AREA RESET, CODE, READONLY
|
||||
ARM
|
||||
|
||||
|
||||
; Exception Vectors
|
||||
; Mapped to Address 0.
|
||||
; Absolute addressing mode must be used.
|
||||
; Dummy Handlers are implemented as infinite loops which can be modified.
|
||||
|
||||
Vectors LDR PC,Reset_Addr
|
||||
LDR PC,Undef_Addr
|
||||
LDR PC,SWI_Addr
|
||||
LDR PC,PAbt_Addr
|
||||
LDR PC,DAbt_Addr
|
||||
NOP ; Reserved Vector
|
||||
LDR PC,IRQ_Addr
|
||||
LDR PC,FIQ_Addr
|
||||
|
||||
Reset_Addr DCD Reset_Handler
|
||||
Undef_Addr DCD Undef_Handler
|
||||
SWI_Addr DCD SWI_Handler
|
||||
PAbt_Addr DCD PAbt_Handler
|
||||
DAbt_Addr DCD DAbt_Handler
|
||||
DCD 0 ; Reserved Address
|
||||
IRQ_Addr DCD IRQ_Handler
|
||||
FIQ_Addr DCD FIQ_Handler
|
||||
|
||||
Undef_Handler B Undef_Handler
|
||||
SWI_Handler B SWI_Handler
|
||||
PAbt_Handler B Abort_Handler
|
||||
DAbt_Handler B Abort_Handler
|
||||
FIQ_Handler B FIQ_Handler
|
||||
|
||||
|
||||
; Reset Handler
|
||||
|
||||
EXPORT Reset_Handler
|
||||
Reset_Handler
|
||||
|
||||
|
||||
; Setup RSTC
|
||||
IF RSTC_SETUP != 0
|
||||
LDR R0, =RSTC_BASE
|
||||
LDR R1, =RSTC_MR_Val
|
||||
STR R1, [R0, #RSTC_MR]
|
||||
ENDIF
|
||||
|
||||
|
||||
; Setup EFC0
|
||||
IF EFC0_SETUP != 0
|
||||
LDR R0, =EFC_BASE
|
||||
LDR R1, =EFC0_FMR_Val
|
||||
STR R1, [R0, #EFC0_FMR]
|
||||
ENDIF
|
||||
|
||||
; Setup EFC1
|
||||
IF EFC1_SETUP != 0
|
||||
LDR R0, =EFC_BASE
|
||||
LDR R1, =EFC1_FMR_Val
|
||||
STR R1, [R0, #EFC1_FMR]
|
||||
ENDIF
|
||||
|
||||
; Setup WDT
|
||||
IF WDT_SETUP != 0
|
||||
LDR R0, =WDT_BASE
|
||||
LDR R1, =WDT_MR_Val
|
||||
STR R1, [R0, #WDT_MR]
|
||||
ENDIF
|
||||
|
||||
|
||||
; Setup PMC
|
||||
IF PMC_SETUP != 0
|
||||
LDR R0, =PMC_BASE
|
||||
|
||||
; Setup Main Oscillator
|
||||
LDR R1, =PMC_MOR_Val
|
||||
STR R1, [R0, #PMC_MOR]
|
||||
|
||||
; Wait until Main Oscillator is stablilized
|
||||
IF (PMC_MOR_Val:AND:PMC_MOSCEN) != 0
|
||||
MOSCS_Loop LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MOSCS
|
||||
BEQ MOSCS_Loop
|
||||
ENDIF
|
||||
|
||||
; Setup the PLL
|
||||
IF (PMC_PLLR_Val:AND:PMC_MUL) != 0
|
||||
LDR R1, =PMC_PLLR_Val
|
||||
STR R1, [R0, #PMC_PLLR]
|
||||
|
||||
; Wait until PLL is stabilized
|
||||
PLL_Loop LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_LOCK
|
||||
BEQ PLL_Loop
|
||||
ENDIF
|
||||
|
||||
; Select Clock
|
||||
IF (PMC_MCKR_Val:AND:PMC_CSS) == 1 ; Main Clock Selected
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
AND R1, #PMC_CSS
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy1
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy2
|
||||
ELIF (PMC_MCKR_Val:AND:PMC_CSS) == 3 ; PLL Clock Selected
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
AND R1, #PMC_PRES
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy1
|
||||
LDR R1, =PMC_MCKR_Val
|
||||
STR R1, [R0, #PMC_MCKR]
|
||||
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
|
||||
ANDS R2, R2, #PMC_MCKRDY
|
||||
BEQ WAIT_Rdy2
|
||||
ENDIF ; Select Clock
|
||||
ENDIF ; PMC_SETUP
|
||||
|
||||
|
||||
; Copy Exception Vectors to Internal RAM
|
||||
|
||||
IF :DEF:RAM_INTVEC
|
||||
ADR R8, Vectors ; Source
|
||||
LDR R9, =RAM_BASE ; Destination
|
||||
LDMIA R8!, {R0-R7} ; Load Vectors
|
||||
STMIA R9!, {R0-R7} ; Store Vectors
|
||||
LDMIA R8!, {R0-R7} ; Load Handler Addresses
|
||||
STMIA R9!, {R0-R7} ; Store Handler Addresses
|
||||
ENDIF
|
||||
|
||||
|
||||
; Remap on-chip RAM to address 0
|
||||
|
||||
MC_BASE EQU 0xFFFFFF00 ; MC Base Address
|
||||
MC_RCR EQU 0x00 ; MC_RCR Offset
|
||||
|
||||
IF :DEF:REMAP
|
||||
LDR R0, =MC_BASE
|
||||
MOV R1, #1
|
||||
STR R1, [R0, #MC_RCR] ; Remap
|
||||
ENDIF
|
||||
|
||||
|
||||
; Setup Stack for each mode
|
||||
|
||||
LDR R0, =Stack_Top
|
||||
|
||||
; Enter Undefined Instruction Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
;SUB R0, R0, #UND_Stack_Size
|
||||
|
||||
; Enter Abort Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
;SUB R0, R0, #ABT_Stack_Size
|
||||
|
||||
; Enter FIQ Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
;SUB R0, R0, #FIQ_Stack_Size
|
||||
|
||||
; Enter IRQ Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
;SUB R0, R0, #IRQ_Stack_Size
|
||||
|
||||
; Enter Supervisor Mode and set its Stack Pointer
|
||||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
|
||||
MOV SP, R0
|
||||
; SUB R0, R0, #SVC_Stack_Size
|
||||
|
||||
; Enter User Mode and set its Stack Pointer
|
||||
; MSR CPSR_c, #Mode_USR
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __initial_sp
|
||||
|
||||
ELSE
|
||||
|
||||
; No usr mode stack here.
|
||||
;MOV SP, R0
|
||||
;SUB SL, SP, #USR_Stack_Size
|
||||
|
||||
ENDIF
|
||||
|
||||
|
||||
; Enter the C code
|
||||
|
||||
IMPORT __main
|
||||
LDR R0, =__main
|
||||
BX R0
|
||||
|
||||
IMPORT rt_interrupt_enter
|
||||
IMPORT rt_interrupt_leave
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
IMPORT rt_hw_trap_irq
|
||||
IMPORT rt_hw_trap_abort
|
||||
IMPORT rt_interrupt_nest
|
||||
|
||||
Abort_Handler PROC
|
||||
EXPORT Abort_Handler
|
||||
stmfd sp!, {r0-r12,lr}
|
||||
LDR r0, =rt_interrupt_nest
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0
|
||||
DeadLoop BHI DeadLoop ; Abort happened in irq mode, halt system.
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_abort
|
||||
bl rt_interrupt_leave
|
||||
b SWITCH
|
||||
ENDP
|
||||
|
||||
IRQ_Handler PROC
|
||||
EXPORT IRQ_Handler
|
||||
STMFD sp!, {r0-r12,lr}
|
||||
BL rt_interrupt_enter
|
||||
BL rt_hw_trap_irq
|
||||
BL rt_interrupt_leave
|
||||
|
||||
; if rt_thread_switch_interrupt_flag set, jump to
|
||||
; rt_hw_context_switch_interrupt_do and don't return
|
||||
SWITCH LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #1
|
||||
BEQ rt_hw_context_switch_interrupt_do
|
||||
|
||||
LDMFD sp!, {r0-r12,lr}
|
||||
SUBS pc, lr, #4
|
||||
ENDP
|
||||
|
||||
; /*
|
||||
; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
|
||||
; */
|
||||
rt_hw_context_switch_interrupt_do PROC
|
||||
EXPORT rt_hw_context_switch_interrupt_do
|
||||
MOV r1, #0 ; clear flag
|
||||
STR r1, [r0]
|
||||
|
||||
LDMFD sp!, {r0-r12,lr}; reload saved registers
|
||||
STMFD sp!, {r0-r3} ; save r0-r3
|
||||
MOV r1, sp
|
||||
ADD sp, sp, #16 ; restore sp
|
||||
SUB r2, lr, #4 ; save old task's pc to r2
|
||||
|
||||
MRS r3, spsr ; get cpsr of interrupt thread
|
||||
|
||||
; switch to SVC mode and no interrupt
|
||||
MSR cpsr_c, #I_Bit|F_Bit|Mode_SVC
|
||||
|
||||
STMFD sp!, {r2} ; push old task's pc
|
||||
STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4
|
||||
MOV r4, r1 ; Special optimised code below
|
||||
MOV r5, r3
|
||||
LDMFD r4!, {r0-r3}
|
||||
STMFD sp!, {r0-r3} ; push old task's r3-r0
|
||||
STMFD sp!, {r5} ; push old task's cpsr
|
||||
MRS r4, spsr
|
||||
STMFD sp!, {r4} ; push old task's spsr
|
||||
|
||||
LDR r4, =rt_interrupt_from_thread
|
||||
LDR r5, [r4]
|
||||
STR sp, [r5] ; store sp in preempted tasks's TCB
|
||||
|
||||
LDR r6, =rt_interrupt_to_thread
|
||||
LDR r6, [r6]
|
||||
LDR sp, [r6] ; get new task's stack pointer
|
||||
|
||||
LDMFD sp!, {r4} ; pop new task's spsr
|
||||
MSR spsr_cxsf, r4
|
||||
LDMFD sp!, {r4} ; pop new task's psr
|
||||
MSR cpsr_cxsf, r4
|
||||
|
||||
LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
|
||||
ENDP
|
||||
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __heap_base
|
||||
EXPORT __heap_limit
|
||||
|
||||
ELSE
|
||||
; User Initial Stack & Heap
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
EXPORT __user_initial_stackheap
|
||||
__user_initial_stackheap
|
||||
|
||||
LDR R0, = Heap_Mem
|
||||
LDR R1, = (Stack_Mem + IRQ_Stack_Size)
|
||||
LDR R2, = (Heap_Mem + Heap_Size)
|
||||
LDR R3, = Stack_Mem
|
||||
BX LR
|
||||
ENDIF
|
||||
|
||||
END
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2006-08-25 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#include "AT91SAM7X256.h"
|
||||
|
||||
/**
|
||||
* @addtogroup AT91SAM7
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
void rt_hw_trap_irq(void)
|
||||
{
|
||||
int irqno;
|
||||
extern struct rt_irq_desc irq_desc[];
|
||||
|
||||
/* get interrupt number */
|
||||
irqno = AT91C_BASE_AIC->AIC_ISR;
|
||||
|
||||
/* invoke isr with parameters */
|
||||
irq_desc[irqno].handler(irqno, irq_desc[irqno].param);
|
||||
|
||||
/* end of interrupt */
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq(void)
|
||||
{
|
||||
rt_kprintf("fast interrupt request\n");
|
||||
}
|
||||
|
||||
extern struct rt_thread* rt_current_thread;
|
||||
void rt_hw_trap_abort(void)
|
||||
{
|
||||
rt_kprintf("Abort occured!!! Thread [%s] suspended.\n",rt_current_thread->name);
|
||||
rt_thread_suspend(rt_current_thread);
|
||||
rt_schedule();
|
||||
|
||||
}
|
||||
/*@}*/
|
||||
@@ -0,0 +1,18 @@
|
||||
# RT-Thread building script for bridge
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
list = os.listdir(cwd)
|
||||
|
||||
# add common code files
|
||||
group = SConscript(os.path.join('common', 'SConscript'))
|
||||
|
||||
# cpu porting code files
|
||||
if rtconfig.CPU in list:
|
||||
group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript'))
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __AM33XX_H__
|
||||
#define __AM33XX_H__
|
||||
|
||||
#define REG32(x) (*((volatile unsigned int *)(x)))
|
||||
#define REG16(x) (*((volatile unsigned short *)(x)))
|
||||
|
||||
/** Cache Line size in ARM Cortex-A8. */
|
||||
#define AM33XX_CACHELINE_SIZE (64)
|
||||
|
||||
/** @brief Base address of AINTC memory mapped registers */
|
||||
#define AM33XX_AINTC_REGS (0x48200000)
|
||||
|
||||
|
||||
/** @brief Base addresses of control module registers */
|
||||
#define AM33XX_CTLM_REGS (0x44e10000)
|
||||
|
||||
/** @brief Base addresses of USB memory mapped registers */
|
||||
#define AM33XX_USB_0_BASE (0x47401400)
|
||||
#define AM33XX_USB_1_BASE (0x47401C00)
|
||||
/** @brief Base addresses of SPI memory mapped registers */
|
||||
#define AM33XX_SPI_0_REGS (0x48030000)
|
||||
#define AM33XX_SPI_1_REGS (0x481A0000)
|
||||
|
||||
/** @brief Base addresses of GPIO memory mapped registers */
|
||||
#define AM33XX_GPIO_0_REGS (0x44E07000)
|
||||
#define AM33XX_GPIO_1_REGS (0x4804C000)
|
||||
#define AM33XX_GPIO_2_REGS (0x481AC000)
|
||||
#define AM33XX_GPIO_3_REGS (0x481AE000)
|
||||
|
||||
/** @brief Base addresses of DMTIMER memory mapped registers */
|
||||
#define AM33XX_DMTIMER_0_REGS (0x44E05000)
|
||||
#define AM33XX_DMTIMER_1_REGS (0x44E31000)
|
||||
#define AM33XX_DMTIMER_2_REGS (0x48040000)
|
||||
#define AM33XX_DMTIMER_3_REGS (0x48042000)
|
||||
#define AM33XX_DMTIMER_4_REGS (0x48044000)
|
||||
#define AM33XX_DMTIMER_5_REGS (0x48046000)
|
||||
#define AM33XX_DMTIMER_6_REGS (0x48048000)
|
||||
#define AM33XX_DMTIMER_7_REGS (0x4804A000)
|
||||
|
||||
/** @brief Base address of MMC memory mapped registers */
|
||||
#define AM33XX_MMCHS_0_REGS (0x48060000)
|
||||
#define AM33XX_MMCHS_1_REGS (0x481D8000)
|
||||
#define AM33XX_MMCHS_2_REGS (0x47810000)
|
||||
|
||||
/** @brief Base address of GPMC memory mapped registers */
|
||||
#define AM33XX_GPMC_0_REGS (0x50000000)
|
||||
|
||||
/** @brief Base address of GPMC memory mapped registers */
|
||||
#define AM33XX_ELM_0_REGS (0x48080000)
|
||||
|
||||
/** @brief Base address of I2C memory mapped registers */
|
||||
#define AM33XX_I2C_0_REGS (0x44E0B000)
|
||||
#define AM33XX_I2C_1_REGS (0x4802A000)
|
||||
#define AM33XX_I2C_2_REGS (0x4819C000)
|
||||
|
||||
/** @brief Base address of WDT memory mapped registers */
|
||||
#define AM33XX_WDT_0_REGS (0x44E33000)
|
||||
#define AM33XX_WDT_1_REGS (0x44E35000)
|
||||
|
||||
/** @brief Base address of WDT memory mapped registers */
|
||||
#define AM33XX_CPSW_SS_REGS (0x4A100000)
|
||||
#define AM33XX_CPSW_MDIO_REGS (0x4A101000)
|
||||
#define AM33XX_CPSW_WR_REGS (0x4A101200)
|
||||
#define AM33XX_CPSW_CPDMA_REGS (0x4A100800)
|
||||
#define AM33XX_CPSW_ALE_REGS (0x4A100D00)
|
||||
#define AM33XX_CPSW_STAT_REGS (0x4A100900)
|
||||
#define AM33XX_CPSW_PORT_0_REGS (0x4A100100)
|
||||
#define AM33XX_CPSW_PORT_1_REGS (0x4A100200)
|
||||
#define AM33XX_CPSW_SLIVER_1_REGS (0x4A100D80)
|
||||
#define AM33XX_CPSW_PORT_2_REGS (0x4A100300)
|
||||
#define AM33XX_CPSW_SLIVER_2_REGS (0x4A100DC0)
|
||||
#define AM33XX_CPSW_CPPI_RAM_REGS (0x4A102000)
|
||||
|
||||
/** @brief Base address of McASP memory mapped registers */
|
||||
#define AM33XX_MCASP_1_CTRL_REGS (0x4803C000)
|
||||
#define AM33XX_MCASP_1_FIFO_REGS (AM33XX_MCASP_1_CTRL_REGS + 0x1000)
|
||||
#define AM33XX_MCASP_1_DATA_REGS (0x46400000)
|
||||
|
||||
/** @brief Base address of EMIF memory mapped registers */
|
||||
#define AM33XX_EMIF_0_REGS (0x4C000000)
|
||||
|
||||
/** @brief Base addresses of RTC memory mapped registers */
|
||||
#define AM33XX_RTC_0_REGS (0x44E3E000)
|
||||
|
||||
#define CM_PER(base) ((base) + 0)
|
||||
#define CM_PER_L4LS_CLKSTCTRL(base) (CM_PER(base) + 0)
|
||||
#define CM_PER_UART1_CLKCTRL(base) (CM_PER(base) + 0x6C)
|
||||
#define CM_PER_UART2_CLKCTRL(base) (CM_PER(base) + 0x70)
|
||||
#define CM_PER_UART3_CLKCTRL(base) (CM_PER(base) + 0x74)
|
||||
#define CM_PER_UART4_CLKCTRL(base) (CM_PER(base) + 0x78)
|
||||
#define CM_PER_UART5_CLKCTRL(base) (CM_PER(base) + 0x38)
|
||||
#define CM_WKUP(base) ((base) + 0x400)
|
||||
#define CM_DPLL(base) ((base) + 0x500)
|
||||
#define CM_MPU(base) ((base) + 0x600)
|
||||
#define CM_DEVICE(base) ((base) + 0x700)
|
||||
#define CM_RTC(base) ((base) + 0x800)
|
||||
#define CM_GFX(base) ((base) + 0x900)
|
||||
#define CM_CEFUSE(base) ((base) + 0xA00)
|
||||
#define OCP_AM33XXKET_RAM(base) ((base) + 0xB00)
|
||||
#define PRM_PER(base) ((base) + 0xC00)
|
||||
#define PRM_PER_PWRSTST(base) (PRM_PER(base) + 0x008)
|
||||
#define PRM_PER_PWRSTCTRL(base) (PRM_PER(base) + 0x00C)
|
||||
#define PRM_WKUP(base) ((base) + 0xD00)
|
||||
#define PRM_MPU(base) ((base) + 0xE00)
|
||||
#define PRM_DEVICE(base) ((base) + 0xF00)
|
||||
#define PRM_RTC(base) ((base) + 0x1000)
|
||||
#define PRM_GFX(base) ((base) + 0x1100)
|
||||
#define PRM_CEFUSE(base) ((base) + 0x1200)
|
||||
|
||||
/** @brief Base addresses of PRCM memory mapped registers */
|
||||
#define AM33XX_PRCM_REGS (0x44E00000)
|
||||
#define AM33XX_CM_PER_REGS CM_PER(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_CM_WKUP_REGS CM_WKUP(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_CM_DPLL_REGS CM_DPLL(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_CM_MPU_REGS CM_MPU(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_CM_DEVICE_REGS CM_DEVICE(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_CM_RTC_REGS CM_RTC(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_CM_GFX_REGS CM_GFX(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_CM_CEFUSE_REGS CM_CEFUSE(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_OCP_AM33XXKET_RAM_REGS OCP_AM33XXKET_RAM(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_PRM_PER_REGS PRM_PER(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_PRM_WKUP_REGS PRM_WKUP(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_PRM_MPU_REGS PRM_MPU(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_PRM_DEVICE_REGS PRM_DEVICE(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_PRM_RTC_REGS PRM_RTC(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_PRM_GFX_REGS PRM_GFX(AM33XX_PRCM_REGS)
|
||||
#define AM33XX_PRM_CEFUSE_REGS PRM_CEFUSE(AM33XX_PRCM_REGS)
|
||||
|
||||
/** @brief Base address of control module memory mapped registers */
|
||||
#define AM33XX_CONTROL_REGS (0x44E10000)
|
||||
|
||||
|
||||
/** @brief Base address of Channel controller memory mapped registers */
|
||||
#define AM33XX_EDMA30CC_0_REGS (0x49000000)
|
||||
|
||||
/** @brief Base address of DCAN module memory mapped registers */
|
||||
#define AM33XX_DCAN_0_REGS (0x481CC000)
|
||||
#define AM33XX_DCAN_1_REGS (0x481D0000)
|
||||
|
||||
/******************************************************************************\
|
||||
* Parameterizable Configuration:- These are fed directly from the RTL
|
||||
* parameters for the given AM33XX
|
||||
\******************************************************************************/
|
||||
#define TPCC_MUX(n) 0xF90 + ((n) * 4)
|
||||
|
||||
|
||||
#define AM33XX_LCDC_0_REGS 0x4830E000
|
||||
|
||||
#define AM33XX_ADC_TSC_0_REGS 0x44E0D000
|
||||
|
||||
/** @brief Base addresses of PWMSS memory mapped registers. */
|
||||
|
||||
#define AM33XX_PWMSS0_REGS (0x48300000)
|
||||
#define AM33XX_PWMSS1_REGS (0x48302000)
|
||||
#define AM33XX_PWMSS2_REGS (0x48304000)
|
||||
|
||||
#define AM33XX_ECAP_REGS (0x00000100)
|
||||
#define AM33XX_EQEP_REGS (0x00000180)
|
||||
#define AM33XX_EPWM_REGS (0x00000200)
|
||||
|
||||
#define AM33XX_ECAP_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_ECAP_REGS)
|
||||
#define AM33XX_ECAP_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_ECAP_REGS)
|
||||
#define AM33XX_ECAP_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_ECAP_REGS)
|
||||
|
||||
#define AM33XX_EQEP_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_EQEP_REGS)
|
||||
#define AM33XX_EQEP_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_EQEP_REGS)
|
||||
#define AM33XX_EQEP_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_EQEP_REGS)
|
||||
|
||||
#define AM33XX_EPWM_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_EPWM_REGS)
|
||||
#define AM33XX_EPWM_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_EPWM_REGS)
|
||||
#define AM33XX_EPWM_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_EPWM_REGS)
|
||||
|
||||
#define AM33XX_EPWM_MODULE_FREQ 100
|
||||
|
||||
/* PRCM registers */
|
||||
#define CM_PER_L4LS_CLKSTCTRL_REG(base) REG32((base) + 0x0)
|
||||
#define CM_PER_UART1_CLKCTRL_REG(base) REG32(CM_PER_UART1_CLKCTRL(base))
|
||||
#define CM_PER_UART2_CLKCTRL_REG(base) REG32(CM_PER_UART2_CLKCTRL(base))
|
||||
#define CM_PER_UART3_CLKCTRL_REG(base) REG32(CM_PER_UART3_CLKCTRL(base))
|
||||
#define CM_PER_UART4_CLKCTRL_REG(base) REG32(CM_PER_UART4_CLKCTRL(base))
|
||||
#define CM_PER_UART5_CLKCTRL_REG(base) REG32(CM_PER_UART5_CLKCTRL(base))
|
||||
|
||||
#define CM_PER_TIMER7_CLKCTRL(base) REG32((base) + 0x7C)
|
||||
#define CM_PER_TIMER2_CLKCTRL(base) REG32((base) + 0x80)
|
||||
|
||||
#define PRM_PER_PWRSTST_REG(base) REG32(PRM_PER_PWRSTST(base))
|
||||
#define PRM_PER_PWRSTCTRL_REG(base) REG32(PRM_PER_PWRSTCTRL(base))
|
||||
|
||||
#define CM_DPLL_CLKSEL_TIMER7_CLK(base) REG32(CM_DPLL(base) + 0x4)
|
||||
#define CM_DPLL_CLKSEL_TIMER2_CLK(base) REG32(CM_DPLL(base) + 0x8)
|
||||
|
||||
/* timer registers */
|
||||
#define DMTIMER_TIDR(base) REG32(base + 0x0)
|
||||
#define DMTIMER_TIOCP_CFG(base) REG32(base + 0x10)
|
||||
#define DMTIMER_IRQ_EOI(base) REG32(base + 0x20)
|
||||
#define DMTIMER_IRQSTATUS_RAW(base) REG32(base + 0x24)
|
||||
#define DMTIMER_IRQSTATUS(base) REG32(base + 0x28)
|
||||
#define DMTIMER_IRQENABLE_SET(base) REG32(base + 0x2C)
|
||||
#define DMTIMER_IRQENABLE_CLR(base) REG32(base + 0x30)
|
||||
#define DMTIMER_IRQWAKEEN(base) REG32(base + 0x34)
|
||||
#define DMTIMER_TCLR(base) REG32(base + 0x38)
|
||||
#define DMTIMER_TCRR(base) REG32(base + 0x3C)
|
||||
#define DMTIMER_TLDR(base) REG32(base + 0x40)
|
||||
#define DMTIMER_TTGR(base) REG32(base + 0x44)
|
||||
#define DMTIMER_TWPS(base) REG32(base + 0x48)
|
||||
#define DMTIMER_TMAR(base) REG32(base + 0x4C)
|
||||
#define DMTIMER_TCAR(base, n) REG32(base + 0x50 + (((n) - 1) * 8))
|
||||
#define DMTIMER_TSICR(base) REG32(base + 0x54)
|
||||
|
||||
#define EMU_INT 0
|
||||
#define COMMTX_INT 1
|
||||
#define COMMRX_INT 2
|
||||
#define BENCH_INT 3
|
||||
#define ELM_IRQ_INT 4
|
||||
#define NMI_INT 7
|
||||
#define L3DEBUG_INT 9
|
||||
#define L3APP_INT 10
|
||||
#define PRCM_INT 11
|
||||
#define EDMACOMP_INT 12
|
||||
#define EDMAMPERR_INT 13
|
||||
#define EDMAERR_INT 14
|
||||
#define ADC_TSC_GEN_INT 16
|
||||
#define USBSS_INT 17
|
||||
#define USB_INT0 18
|
||||
#define USB_INT1 19
|
||||
#define PRU_ICSS_EVTOUT0_INT 20
|
||||
#define PRU_ICSS_EVTOUT1_INT 21
|
||||
#define PRU_ICSS_EVTOUT2_INT 22
|
||||
#define PRU_ICSS_EVTOUT3_INT 23
|
||||
#define PRU_ICSS_EVTOUT4_INT 24
|
||||
#define PRU_ICSS_EVTOUT5_INT 25
|
||||
#define PRU_ICSS_EVTOUT6_INT 26
|
||||
#define PRU_ICSS_EVTOUT7_INT 27
|
||||
#define MMCSD1_INT 28
|
||||
#define MMCSD2_INT 29
|
||||
#define I2C2_INT 30
|
||||
#define ECAP0_INT 31
|
||||
#define GPIO_INT2A 32
|
||||
#define GPIO_INT2B 33
|
||||
#define USBWAKEUP_INT 34
|
||||
#define LCDC_INT 36
|
||||
#define GFX_INT 37
|
||||
#define EPWM2_INT 39
|
||||
#define CPSW_RXTHR0_INT 40
|
||||
#define CPSW_RX_INT0 41
|
||||
#define CPSW_TX_INT0 42
|
||||
#define CPSW_MISC0_INT 43
|
||||
#define UART3_INT 44
|
||||
#define UART4_INT 45
|
||||
#define UART5_INT 46
|
||||
#define ECAP1_INT 47
|
||||
#define DCAN0_INT0 52
|
||||
#define DCAN0_INT1 53
|
||||
#define DCAN0_PARITY 54
|
||||
#define DCAN1_INT0 55
|
||||
#define DCAN1_INT1 56
|
||||
#define DCAN1_PARITY 57
|
||||
#define EPWM0_TZINT 58
|
||||
#define EPWM1_TZINT 59
|
||||
#define EPWM2_TZINT 60
|
||||
#define ECAP2_INT 61
|
||||
#define GPIO_INT3A 62
|
||||
#define GPIO_INT3B 63
|
||||
#define MMCSD0_INT 64
|
||||
#define MCSPI0_INT 65
|
||||
#define TINT0 66
|
||||
#define TINT1_1MS 67
|
||||
#define TINT2 68
|
||||
#define TINT3 69
|
||||
#define I2C0_INT 70
|
||||
#define I2C1_INT 71
|
||||
#define UART0_INT 72
|
||||
#define UART1_INT 73
|
||||
#define UART2_INT 74
|
||||
#define RTC_INT 75
|
||||
#define RTC_ALARM_INT 76
|
||||
#define MB_INT0 77
|
||||
#define M3_TXEV 78
|
||||
#define EQEP0_INT 79
|
||||
#define MACTX_INT0 80
|
||||
#define MCARX_INT0 81
|
||||
#define MCATX_INT1 82
|
||||
#define MCARX_INT1 83
|
||||
#define EPWM0_INT 86
|
||||
#define EPWM1_INT 87
|
||||
#define EQEP1_INT 88
|
||||
#define EQEP2_INT 89
|
||||
#define DMA_INTR_PIN2 90
|
||||
#define WDT1_INT 91
|
||||
#define TINT4 92
|
||||
#define TINT5 93
|
||||
#define TINT6 94
|
||||
#define TINT7 95
|
||||
#define GPIO_INT0A 96
|
||||
#define GPIO_INT0B 97
|
||||
#define GPIO_INT1A 98
|
||||
#define GPIO_INT1B 99
|
||||
#define GPMC_INT 100
|
||||
#define DDRERR0 101
|
||||
#define TCERR_INT0 112
|
||||
#define TCERR_INT1 113
|
||||
#define TCERR_INT2 114
|
||||
#define ADC_TSC_PEN_INT 115
|
||||
#define SMRFLX_MPU 120
|
||||
#define SMRFLX_CORE 121
|
||||
#define DMA_INTR_PIN0 123
|
||||
#define DMA_INTR_PIN1 124
|
||||
#define MCSPI1_INT 125
|
||||
|
||||
struct rt_hw_register
|
||||
{
|
||||
unsigned long r0;
|
||||
unsigned long r1;
|
||||
unsigned long r2;
|
||||
unsigned long r3;
|
||||
unsigned long r4;
|
||||
unsigned long r5;
|
||||
unsigned long r6;
|
||||
unsigned long r7;
|
||||
unsigned long r8;
|
||||
unsigned long r9;
|
||||
unsigned long r10;
|
||||
unsigned long fp;
|
||||
unsigned long ip;
|
||||
unsigned long sp;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
unsigned long cpsr;
|
||||
unsigned long ORIG_r0;
|
||||
};
|
||||
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
mrs r0, cpsr
|
||||
cpsid if
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
msr cpsr_c, r0
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
|
||||
stmfd sp!, {r0-r12, lr} @ push lr & register file
|
||||
|
||||
mrs r4, cpsr
|
||||
tst lr, #0x01
|
||||
orrne r4, r4, #0x20 @ it's thumb code
|
||||
|
||||
stmfd sp!, {r4} @ push cpsr
|
||||
|
||||
str sp, [r0] @ store sp in preempted tasks TCB
|
||||
ldr sp, [r1] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task cpsr to spsr
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
_do_switch:
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
ldr sp, [r0] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
bic r4, r4, #0x20 @ must be ARM mode
|
||||
msr cpsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
str r3, [r2]
|
||||
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
str r0, [r2]
|
||||
_reswitch:
|
||||
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
@@ -0,0 +1,82 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-08-14 weety copy from mini2440
|
||||
; * 2015-04-15 ArdaFu convert from context_gcc.s
|
||||
; */
|
||||
|
||||
#define NOINT 0xc0
|
||||
|
||||
SECTION .text:CODE(6)
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
PUBLIC rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, CPSR
|
||||
ORR R1, R0, #NOINT
|
||||
MSR CPSR_C, R1
|
||||
MOV PC, LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
PUBLIC rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR CPSR_CXSF, R0
|
||||
MOV PC, LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
PUBLIC rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
STMFD SP!, {LR} ; push pc (lr should be pushed in place of PC)
|
||||
STMFD SP!, {R0-R12, LR} ; push lr & register file
|
||||
MRS R4, CPSR
|
||||
STMFD SP!, {R4} ; push cpsr
|
||||
STR SP, [R0] ; store sp in preempted tasks TCB
|
||||
LDR SP, [R1] ; get new task stack pointer
|
||||
LDMFD SP!, {R4} ; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
PUBLIC rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR SP, [R0] ; get new task stack pointer
|
||||
LDMFD SP!, {R4} ; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
PUBLIC rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOV R3, #1 ; set flag to 1
|
||||
STR R3, [R2]
|
||||
LDR R2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR R0, [R2]
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR R1, [R2]
|
||||
MOV PC, LR
|
||||
END
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
.globl rt_cpu_vector_set_base
|
||||
rt_cpu_vector_set_base:
|
||||
mcr p15, #0, r0, c12, c0, #0
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_vector_get_base
|
||||
rt_cpu_vector_get_base:
|
||||
mrc p15, #0, r0, c12, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_get_sctlr
|
||||
rt_cpu_get_sctlr:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_dcache_enable
|
||||
rt_cpu_dcache_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x00000004
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_icache_enable
|
||||
rt_cpu_icache_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x00001000
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
_FLD_MAX_WAY:
|
||||
.word 0x3ff
|
||||
_FLD_MAX_IDX:
|
||||
.word 0x7ff
|
||||
|
||||
.globl rt_cpu_dcache_clean_flush
|
||||
rt_cpu_dcache_clean_flush:
|
||||
push {r4-r11}
|
||||
dmb
|
||||
mrc p15, #1, r0, c0, c0, #1 @ read clid register
|
||||
ands r3, r0, #0x7000000 @ get level of coherency
|
||||
mov r3, r3, lsr #23
|
||||
beq finished
|
||||
mov r10, #0
|
||||
loop1:
|
||||
add r2, r10, r10, lsr #1
|
||||
mov r1, r0, lsr r2
|
||||
and r1, r1, #7
|
||||
cmp r1, #2
|
||||
blt skip
|
||||
mcr p15, #2, r10, c0, c0, #0
|
||||
isb
|
||||
mrc p15, #1, r1, c0, c0, #0
|
||||
and r2, r1, #7
|
||||
add r2, r2, #4
|
||||
ldr r4, _FLD_MAX_WAY
|
||||
ands r4, r4, r1, lsr #3
|
||||
clz r5, r4
|
||||
ldr r7, _FLD_MAX_IDX
|
||||
ands r7, r7, r1, lsr #13
|
||||
loop2:
|
||||
mov r9, r4
|
||||
loop3:
|
||||
orr r11, r10, r9, lsl r5
|
||||
orr r11, r11, r7, lsl r2
|
||||
mcr p15, #0, r11, c7, c14, #2
|
||||
subs r9, r9, #1
|
||||
bge loop3
|
||||
subs r7, r7, #1
|
||||
bge loop2
|
||||
skip:
|
||||
add r10, r10, #2
|
||||
cmp r3, r10
|
||||
bgt loop1
|
||||
|
||||
finished:
|
||||
dsb
|
||||
isb
|
||||
pop {r4-r11}
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_dcache_disable
|
||||
rt_cpu_dcache_disable:
|
||||
push {r4-r11, lr}
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #0x00000004
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bl rt_cpu_dcache_clean_flush
|
||||
pop {r4-r11, lr}
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_icache_disable
|
||||
rt_cpu_icache_disable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #0x00001000
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_mmu_disable
|
||||
rt_cpu_mmu_disable:
|
||||
mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #1
|
||||
mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_mmu_enable
|
||||
rt_cpu_mmu_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x001
|
||||
mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_tlb_set
|
||||
rt_cpu_tlb_set:
|
||||
mcr p15, #0, r0, c2, c0, #0
|
||||
dmb
|
||||
bx lr
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-04-06 zchong change to iar compiler from convert from cp15_gcc.S
|
||||
*/
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
ARM
|
||||
|
||||
EXPORT rt_cpu_vector_set_base
|
||||
rt_cpu_vector_set_base:
|
||||
MCR p15, #0, r0, c12, c0, #0
|
||||
DSB
|
||||
BX lr
|
||||
|
||||
EXPORT rt_cpu_vector_get_base
|
||||
rt_cpu_vector_get_base:
|
||||
MRC p15, #0, r0, c12, c0, #0
|
||||
BX lr
|
||||
|
||||
EXPORT rt_cpu_get_sctlr
|
||||
rt_cpu_get_sctlr:
|
||||
MRC p15, #0, r0, c1, c0, #0
|
||||
BX lr
|
||||
|
||||
EXPORT rt_cpu_dcache_enable
|
||||
rt_cpu_dcache_enable:
|
||||
MRC p15, #0, r0, c1, c0, #0
|
||||
ORR r0, r0, #0x00000004
|
||||
MCR p15, #0, r0, c1, c0, #0
|
||||
BX lr
|
||||
|
||||
EXPORT rt_cpu_icache_enable
|
||||
rt_cpu_icache_enable:
|
||||
MRC p15, #0, r0, c1, c0, #0
|
||||
ORR r0, r0, #0x00001000
|
||||
MCR p15, #0, r0, c1, c0, #0
|
||||
BX lr
|
||||
|
||||
;_FLD_MAX_WAY DEFINE 0x3ff
|
||||
;_FLD_MAX_IDX DEFINE 0x7ff
|
||||
|
||||
|
||||
EXPORT rt_cpu_dcache_clean_flush
|
||||
rt_cpu_dcache_clean_flush:
|
||||
PUSH {r4-r11}
|
||||
DMB
|
||||
MRC p15, #1, r0, c0, c0, #1 ; read clid register
|
||||
ANDS r3, r0, #0x7000000 ; get level of coherency
|
||||
MOV r3, r3, lsr #23
|
||||
BEQ finished
|
||||
MOV r10, #0
|
||||
loop1:
|
||||
ADD r2, r10, r10, lsr #1
|
||||
MOV r1, r0, lsr r2
|
||||
AND r1, r1, #7
|
||||
CMP r1, #2
|
||||
BLT skip
|
||||
MCR p15, #2, r10, c0, c0, #0
|
||||
ISB
|
||||
MRC p15, #1, r1, c0, c0, #0
|
||||
AND r2, r1, #7
|
||||
ADD r2, r2, #4
|
||||
;LDR r4, _FLD_MAX_WAY
|
||||
LDR r4, =0x3FF
|
||||
ANDS r4, r4, r1, lsr #3
|
||||
CLZ r5, r4
|
||||
;LDR r7, _FLD_MAX_IDX
|
||||
LDR r7, =0x7FF
|
||||
ANDS r7, r7, r1, lsr #13
|
||||
loop2:
|
||||
MOV r9, r4
|
||||
loop3:
|
||||
ORR r11, r10, r9, lsl r5
|
||||
ORR r11, r11, r7, lsl r2
|
||||
MCR p15, #0, r11, c7, c14, #2
|
||||
SUBS r9, r9, #1
|
||||
BGE loop3
|
||||
SUBS r7, r7, #1
|
||||
BGE loop2
|
||||
skip:
|
||||
ADD r10, r10, #2
|
||||
CMP r3, r10
|
||||
BGT loop1
|
||||
|
||||
finished:
|
||||
DSB
|
||||
ISB
|
||||
POP {r4-r11}
|
||||
BX lr
|
||||
|
||||
|
||||
EXPORT rt_cpu_dcache_disable
|
||||
rt_cpu_dcache_disable:
|
||||
PUSH {r4-r11, lr}
|
||||
MRC p15, #0, r0, c1, c0, #0
|
||||
BIC r0, r0, #0x00000004
|
||||
MCR p15, #0, r0, c1, c0, #0
|
||||
BL rt_cpu_dcache_clean_flush
|
||||
POP {r4-r11, lr}
|
||||
BX lr
|
||||
|
||||
|
||||
EXPORT rt_cpu_icache_disable
|
||||
rt_cpu_icache_disable:
|
||||
MRC p15, #0, r0, c1, c0, #0
|
||||
BIC r0, r0, #0x00001000
|
||||
MCR p15, #0, r0, c1, c0, #0
|
||||
BX lr
|
||||
|
||||
EXPORT rt_cpu_mmu_disable
|
||||
rt_cpu_mmu_disable:
|
||||
MCR p15, #0, r0, c8, c7, #0 ; invalidate tlb
|
||||
MRC p15, #0, r0, c1, c0, #0
|
||||
BIC r0, r0, #1
|
||||
MCR p15, #0, r0, c1, c0, #0 ; clear mmu bit
|
||||
DSB
|
||||
BX lr
|
||||
|
||||
EXPORT rt_cpu_mmu_enable
|
||||
rt_cpu_mmu_enable:
|
||||
MRC p15, #0, r0, c1, c0, #0
|
||||
ORR r0, r0, #0x001
|
||||
MCR p15, #0, r0, c1, c0, #0 ; set mmu enable bit
|
||||
DSB
|
||||
BX lr
|
||||
|
||||
EXPORT rt_cpu_tlb_set
|
||||
rt_cpu_tlb_set:
|
||||
MCR p15, #0, r0, c2, c0, #0
|
||||
DMB
|
||||
BX lr
|
||||
|
||||
END
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-15 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include "am33xx.h"
|
||||
|
||||
/**
|
||||
* @addtogroup AM33xx
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
|
||||
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, i, c1, c0, 0
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
__asm__ __volatile__( \
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"orr r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
:"r" (bit) \
|
||||
:"memory");
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
__asm__ __volatile__( \
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"bic r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
:"r" (bit) \
|
||||
:"memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__CC_ARM)|(__GNUC__)
|
||||
/**
|
||||
* enable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_enable()
|
||||
{
|
||||
cache_enable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_disable()
|
||||
{
|
||||
cache_disable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of I-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_icache_status()
|
||||
{
|
||||
return (cp15_rd() & ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* enable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_enable()
|
||||
{
|
||||
cache_enable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_disable()
|
||||
{
|
||||
cache_disable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of D-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_dcache_status()
|
||||
{
|
||||
return (cp15_rd() & DCACHE_MASK);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
* 2015-11-06 zchong support iar compiler
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "am33xx.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#define AINTC_BASE AM33XX_AINTC_REGS
|
||||
|
||||
#define MAX_HANDLERS 128
|
||||
|
||||
extern volatile rt_uint8_t rt_interrupt_nest;
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
struct rt_irq_desc isr_table[MAX_HANDLERS];
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* @addtogroup AM33xx
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
void rt_dump_aintc(void)
|
||||
{
|
||||
int k;
|
||||
rt_kprintf("active irq %d", INTC_SIR_IRQ(AINTC_BASE));
|
||||
rt_kprintf("\n--- hw mask ---\n");
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", INTC_MIR(AINTC_BASE, k));
|
||||
}
|
||||
rt_kprintf("\n--- hw itr ---\n");
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ", INTC_ITR(AINTC_BASE, k));
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
const unsigned int AM335X_VECTOR_BASE = 0x4030FC00;
|
||||
extern void rt_cpu_vector_set_base(unsigned int addr);
|
||||
#ifdef __ICCARM__
|
||||
extern int __vector;
|
||||
#else
|
||||
extern int system_vectors;
|
||||
#endif
|
||||
|
||||
static void rt_hw_vector_init(void)
|
||||
{
|
||||
unsigned int *dest = (unsigned int *)AM335X_VECTOR_BASE;
|
||||
|
||||
#ifdef __ICCARM__
|
||||
unsigned int *src = (unsigned int *)&__vector;
|
||||
#else
|
||||
unsigned int *src = (unsigned int *)&system_vectors;
|
||||
#endif
|
||||
|
||||
rt_memcpy(dest, src, 16 * 4);
|
||||
rt_cpu_vector_set_base(AM335X_VECTOR_BASE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
/* initialize vector table */
|
||||
rt_hw_vector_init();
|
||||
|
||||
/* init exceptions table */
|
||||
rt_memset(isr_table, 0x00, sizeof(isr_table));
|
||||
|
||||
/* init interrupt nest, and context in thread sp */
|
||||
rt_interrupt_nest = 0;
|
||||
rt_interrupt_from_thread = 0;
|
||||
rt_interrupt_to_thread = 0;
|
||||
rt_thread_switch_interrupt_flag = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_mask(int vector)
|
||||
{
|
||||
INTC_MIR_SET(AINTC_BASE, vector >> 0x05) = 0x1 << (vector & 0x1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will un-mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
INTC_MIR_CLEAR(AINTC_BASE, vector >> 0x05) = 0x1 << (vector & 0x1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will control the interrupt attribute.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_control(int vector, int priority, int route)
|
||||
{
|
||||
int fiq;
|
||||
|
||||
if (route == 0)
|
||||
fiq = 0;
|
||||
else
|
||||
fiq = 1;
|
||||
|
||||
INTC_ILR(AINTC_BASE, vector) = ((priority << 0x02) & 0x1FC) | fiq ;
|
||||
}
|
||||
|
||||
int rt_hw_interrupt_get_active(int fiq_irq)
|
||||
{
|
||||
int ir;
|
||||
if (fiq_irq == INT_FIQ)
|
||||
{
|
||||
ir = INTC_SIR_FIQ(AINTC_BASE) & 0x7f;
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = INTC_SIR_IRQ(AINTC_BASE) & 0x7f;
|
||||
}
|
||||
|
||||
return ir;
|
||||
}
|
||||
|
||||
void rt_hw_interrupt_ack(int fiq_irq)
|
||||
{
|
||||
if (fiq_irq == INT_FIQ)
|
||||
{
|
||||
/* new FIQ generation */
|
||||
INTC_CONTROL(AINTC_BASE) |= 0x02;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* new IRQ generation */
|
||||
INTC_CONTROL(AINTC_BASE) |= 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param new_handler the interrupt service routine to be installed
|
||||
* @param old_handler the old interrupt service routine
|
||||
*/
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name)
|
||||
{
|
||||
rt_isr_handler_t old_handler = RT_NULL;
|
||||
|
||||
if(vector < MAX_HANDLERS)
|
||||
{
|
||||
old_handler = isr_table[vector].handler;
|
||||
|
||||
if (handler != RT_NULL)
|
||||
{
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
|
||||
#endif /* RT_USING_INTERRUPT_INFO */
|
||||
isr_table[vector].handler = handler;
|
||||
isr_table[vector].param = param;
|
||||
}
|
||||
}
|
||||
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will trigger an interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_trigger(int vector)
|
||||
{
|
||||
INTC_ISR_SET(AINTC_BASE, vector>>5) = 1 << (vector & 0x1f);
|
||||
}
|
||||
|
||||
void rt_hw_interrupt_clear(int vector)
|
||||
{
|
||||
INTC_ISR_CLEAR(AINTC_BASE, vector>>5) = 1 << (vector & 0x1f);
|
||||
}
|
||||
|
||||
void rt_dump_isr_table(void)
|
||||
{
|
||||
int idx;
|
||||
for(idx = 0; idx < MAX_HANDLERS; idx++)
|
||||
{
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
rt_kprintf("nr:%4d, name: %*.s, handler: 0x%p, param: 0x%08x\r\n",
|
||||
idx, RT_NAME_MAX, isr_table[idx].name,
|
||||
isr_table[idx].handler, isr_table[idx].param);
|
||||
#else
|
||||
rt_kprintf("nr:%4d, handler: 0x%p, param: 0x%08x\r\n",
|
||||
idx, isr_table[idx].handler, isr_table[idx].param);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*@}*/
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __INTERRUPT_H__
|
||||
#define __INTERRUPT_H__
|
||||
|
||||
#define INT_IRQ 0x00
|
||||
#define INT_FIQ 0x01
|
||||
|
||||
#define INTC_REVISION(hw_base) REG32((hw_base) + 0x0)
|
||||
#define INTC_SYSCONFIG(hw_base) REG32((hw_base) + 0x10)
|
||||
#define INTC_SYSSTATUS(hw_base) REG32((hw_base) + 0x14)
|
||||
#define INTC_SIR_IRQ(hw_base) REG32((hw_base) + 0x40)
|
||||
#define INTC_SIR_FIQ(hw_base) REG32((hw_base) + 0x44)
|
||||
#define INTC_CONTROL(hw_base) REG32((hw_base) + 0x48)
|
||||
#define INTC_PROTECTION(hw_base) REG32((hw_base) + 0x4c)
|
||||
#define INTC_IDLE(hw_base) REG32((hw_base) + 0x50)
|
||||
#define INTC_IRQ_PRIORITY(hw_base) REG32((hw_base) + 0x60)
|
||||
#define INTC_FIQ_PRIORITY(hw_base) REG32((hw_base) + 0x64)
|
||||
#define INTC_THRESHOLD(hw_base) REG32((hw_base) + 0x68)
|
||||
#define INTC_SICR(hw_base) REG32((hw_base) + 0x6c)
|
||||
#define INTC_SCR(hw_base, n) REG32((hw_base) + 0x70 + ((n) * 0x04))
|
||||
#define INTC_ITR(hw_base, n) REG32((hw_base) + 0x80 + ((n) * 0x20))
|
||||
#define INTC_MIR(hw_base, n) REG32((hw_base) + 0x84 + ((n) * 0x20))
|
||||
#define INTC_MIR_CLEAR(hw_base, n) REG32((hw_base) + 0x88 + ((n) * 0x20))
|
||||
#define INTC_MIR_SET(hw_base, n) REG32((hw_base) + 0x8c + ((n) * 0x20))
|
||||
#define INTC_ISR_SET(hw_base, n) REG32((hw_base) + 0x90 + ((n) * 0x20))
|
||||
#define INTC_ISR_CLEAR(hw_base, n) REG32((hw_base) + 0x94 + ((n) * 0x20))
|
||||
#define INTC_PENDING_IRQ(hw_base, n) REG32((hw_base) + 0x98 + ((n) * 0x20))
|
||||
#define INTC_PENDING_FIQ(hw_base, n) REG32((hw_base) + 0x9c + ((n) * 0x20))
|
||||
#define INTC_ILR(hw_base, n) REG32((hw_base) + 0x100 + ((n) * 0x04))
|
||||
|
||||
void rt_hw_interrupt_control(int vector, int priority, int route);
|
||||
int rt_hw_interrupt_get_active(int fiq_irq);
|
||||
void rt_hw_interrupt_ack(int fiq_irq);
|
||||
void rt_hw_interrupt_trigger(int vector);
|
||||
void rt_hw_interrupt_clear(int vector);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-10 bernard porting to AM1808
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "am33xx.h"
|
||||
#include <mmu.h>
|
||||
|
||||
extern void rt_cpu_dcache_disable(void);
|
||||
extern void rt_hw_cpu_dcache_enable(void);
|
||||
extern void rt_cpu_icache_disable(void);
|
||||
extern void rt_hw_cpu_icache_enable(void);
|
||||
extern void rt_cpu_mmu_disable(void);
|
||||
extern void rt_cpu_mmu_enable(void);
|
||||
extern void rt_cpu_tlb_set(register rt_uint32_t i);
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
rt_cpu_dcache_disable();
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
rt_hw_cpu_dcache_enable();
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
rt_cpu_icache_disable();
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
rt_hw_cpu_icache_enable();
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
rt_cpu_mmu_disable();
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
rt_cpu_mmu_enable();
|
||||
}
|
||||
|
||||
void mmu_setttbase(register rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
|
||||
|
||||
value = 0x55555555;
|
||||
asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
|
||||
|
||||
rt_cpu_tlb_set(i);
|
||||
}
|
||||
|
||||
void mmu_set_domain(register rt_uint32_t i)
|
||||
{
|
||||
asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= (1 << 1);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~(1 << 1);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index));
|
||||
}
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~0x1f;
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr));
|
||||
ptr += 32;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~0x1f;
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr));
|
||||
ptr += 32;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0));
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
|
||||
}
|
||||
|
||||
/* level1 page table */
|
||||
static volatile unsigned int _page_table[4*1024] __attribute__((aligned(16*1024)));
|
||||
void mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd, rt_uint32_t paddrStart, rt_uint32_t attr)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile int i,nSec;
|
||||
pTT=(rt_uint32_t *)_page_table+(vaddrStart>>20);
|
||||
nSec=(vaddrEnd>>20)-(vaddrStart>>20);
|
||||
for(i=0;i<=nSec;i++)
|
||||
{
|
||||
*pTT = attr |(((paddrStart>>20)+i)<<20);
|
||||
pTT++;
|
||||
}
|
||||
}
|
||||
|
||||
/* set page table */
|
||||
RT_WEAK void mmu_setmtts(void)
|
||||
{
|
||||
mmu_setmtt(0x00000000, 0xFFFFFFFF, 0x00000000, RW_NCNB); /* None cached for 4G memory */
|
||||
mmu_setmtt(0x80200000, 0x80800000 - 1, 0x80200000, RW_CB); /* 126M cached DDR memory */
|
||||
mmu_setmtt(0x80000000, 0x80200000 - 1, 0x80000000, RW_NCNB); /* 2M none-cached DDR memory */
|
||||
mmu_setmtt(0x402F0000, 0x40300000 - 1, 0x402F0000, RW_CB); /* 63K OnChip memory */
|
||||
}
|
||||
|
||||
void rt_hw_mmu_init(void)
|
||||
{
|
||||
/* disable I/D cache */
|
||||
mmu_disable_dcache();
|
||||
mmu_disable_icache();
|
||||
mmu_disable();
|
||||
mmu_invalidate_tlb();
|
||||
|
||||
mmu_setmtts();
|
||||
|
||||
/* set MMU table address */
|
||||
mmu_setttbase((rt_uint32_t)_page_table);
|
||||
|
||||
/* enables MMU */
|
||||
mmu_enable();
|
||||
|
||||
/* enable Instruction Cache */
|
||||
mmu_enable_icache();
|
||||
|
||||
/* enable Data Cache */
|
||||
mmu_enable_dcache();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-10 bernard porting to AM1808
|
||||
*/
|
||||
|
||||
#ifndef __MMU_H__
|
||||
#define __MMU_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define DESC_SEC (0x2)
|
||||
#define CB (3<<2) //cache_on, write_back
|
||||
#define CNB (2<<2) //cache_on, write_through
|
||||
#define NCB (1<<2) //cache_off,WR_BUF on
|
||||
#define NCNB (0<<2) //cache_off,WR_BUF off
|
||||
#define AP_RW (3<<10) //supervisor=RW, user=RW
|
||||
#define AP_RO (2<<10) //supervisor=RW, user=RO
|
||||
|
||||
#define DOMAIN_FAULT (0x0)
|
||||
#define DOMAIN_CHK (0x1)
|
||||
#define DOMAIN_NOTCHK (0x3)
|
||||
#define DOMAIN0 (0x0<<5)
|
||||
#define DOMAIN1 (0x1<<5)
|
||||
|
||||
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
|
||||
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
|
||||
|
||||
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
|
||||
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
|
||||
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
|
||||
void rt_hw_mmu_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-23 Bernard the first version
|
||||
* 2011-10-05 Bernard add thumb mode
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include "am33xx.h"
|
||||
|
||||
/**
|
||||
* @addtogroup AM33xx
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
.equ Mode_USR, 0x10
|
||||
.equ Mode_FIQ, 0x11
|
||||
.equ Mode_IRQ, 0x12
|
||||
.equ Mode_SVC, 0x13
|
||||
.equ Mode_ABT, 0x17
|
||||
.equ Mode_UND, 0x1B
|
||||
.equ Mode_SYS, 0x1F
|
||||
|
||||
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
|
||||
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
|
||||
|
||||
.equ UND_Stack_Size, 0x00000200
|
||||
.equ SVC_Stack_Size, 0x00000100
|
||||
.equ ABT_Stack_Size, 0x00000000
|
||||
.equ FIQ_Stack_Size, 0x00000000
|
||||
.equ IRQ_Stack_Size, 0x00000100
|
||||
.equ USR_Stack_Size, 0x00000100
|
||||
|
||||
#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
|
||||
FIQ_Stack_Size + IRQ_Stack_Size)
|
||||
|
||||
/* stack */
|
||||
.globl stack_start
|
||||
.globl stack_top
|
||||
|
||||
.align 3
|
||||
stack_start:
|
||||
.rept ISR_Stack_Size
|
||||
.long 0
|
||||
.endr
|
||||
stack_top:
|
||||
|
||||
/* reset entry */
|
||||
.globl _reset
|
||||
_reset:
|
||||
/* set the cpu to SVC32 mode and disable interrupt */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #0x1f
|
||||
orr r0, r0, #0x13
|
||||
msr cpsr_c, r0
|
||||
|
||||
/* setup stack */
|
||||
bl stack_setup
|
||||
|
||||
/* clear .bss */
|
||||
mov r0,#0 /* get a zero */
|
||||
ldr r1,=__bss_start /* bss start */
|
||||
ldr r2,=__bss_end /* bss end */
|
||||
|
||||
bss_loop:
|
||||
cmp r1,r2 /* check if data to clear */
|
||||
strlo r0,[r1],#4 /* clear 4 bytes */
|
||||
blo bss_loop /* loop until done */
|
||||
|
||||
/* call C++ constructors of global objects */
|
||||
ldr r0, =__ctors_start__
|
||||
ldr r1, =__ctors_end__
|
||||
|
||||
ctor_loop:
|
||||
cmp r0, r1
|
||||
beq ctor_end
|
||||
ldr r2, [r0], #4
|
||||
stmfd sp!, {r0-r1}
|
||||
mov lr, pc
|
||||
bx r2
|
||||
ldmfd sp!, {r0-r1}
|
||||
b ctor_loop
|
||||
ctor_end:
|
||||
|
||||
/* start RT-Thread Kernel */
|
||||
ldr pc, _rtthread_startup
|
||||
_rtthread_startup:
|
||||
.word rtthread_startup
|
||||
|
||||
stack_setup:
|
||||
ldr r0, =stack_top
|
||||
|
||||
@ Enter Undefined Instruction Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_UND|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #UND_Stack_Size
|
||||
|
||||
@ Enter Abort Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_ABT|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #ABT_Stack_Size
|
||||
|
||||
@ Enter FIQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #FIQ_Stack_Size
|
||||
|
||||
@ Enter IRQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #IRQ_Stack_Size
|
||||
|
||||
@ Enter Supervisor Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #SVC_Stack_Size
|
||||
|
||||
@ Enter User Mode and set its Stack Pointer
|
||||
mov sp, r0
|
||||
sub sl, sp, #USR_Stack_Size
|
||||
bx lr
|
||||
|
||||
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
|
||||
.align 5
|
||||
.globl vector_undef
|
||||
vector_undef:
|
||||
sub sp, sp, #72
|
||||
stmia sp, {r0 - r12} @/* Calling r0-r12 */
|
||||
add r8, sp, #60
|
||||
|
||||
mrs r1, cpsr
|
||||
mrs r2, spsr
|
||||
orr r2,r2, #I_Bit|F_Bit
|
||||
msr cpsr_c, r2
|
||||
mov r0, r0
|
||||
stmdb r8, {sp, lr} @/* Calling SP, LR */
|
||||
msr cpsr_c, r1 @/* return to Undefined Instruction mode */
|
||||
|
||||
str lr, [r8, #0] @/* Save calling PC */
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4] @/* Save CPSR */
|
||||
str r0, [r8, #8] @/* Save OLD_R0 */
|
||||
mov r0, sp
|
||||
|
||||
bl rt_hw_trap_udef
|
||||
|
||||
ldmia sp, {r0 - r12} @/* Calling r0 - r2 */
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #60] @/* Get PC */
|
||||
add sp, sp, #72
|
||||
movs pc, lr @/* return & move spsr_svc into cpsr */
|
||||
|
||||
.align 5
|
||||
.globl vector_swi
|
||||
vector_swi:
|
||||
bl rt_hw_trap_swi
|
||||
|
||||
.align 5
|
||||
.globl vector_pabt
|
||||
vector_pabt:
|
||||
bl rt_hw_trap_pabt
|
||||
|
||||
.align 5
|
||||
.globl vector_dabt
|
||||
vector_dabt:
|
||||
sub sp, sp, #72
|
||||
stmia sp, {r0 - r12} @/* Calling r0-r12 */
|
||||
add r8, sp, #60
|
||||
stmdb r8, {sp, lr} @/* Calling SP, LR */
|
||||
str lr, [r8, #0] @/* Save calling PC */
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4] @/* Save CPSR */
|
||||
str r0, [r8, #8] @/* Save OLD_R0 */
|
||||
mov r0, sp
|
||||
|
||||
bl rt_hw_trap_dabt
|
||||
|
||||
ldmia sp, {r0 - r12} @/* Calling r0 - r2 */
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #60] @/* Get PC */
|
||||
add sp, sp, #72
|
||||
movs pc, lr @/* return & move spsr_svc into cpsr */
|
||||
|
||||
.align 5
|
||||
.globl vector_resv
|
||||
vector_resv:
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_fiq
|
||||
vector_fiq:
|
||||
stmfd sp!,{r0-r7,lr}
|
||||
bl rt_hw_trap_fiq
|
||||
ldmfd sp!,{r0-r7,lr}
|
||||
subs pc,lr,#4
|
||||
|
||||
.globl rt_interrupt_enter
|
||||
.globl rt_interrupt_leave
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
|
||||
.globl rt_current_thread
|
||||
.globl vmm_thread
|
||||
.globl vmm_virq_check
|
||||
|
||||
.globl vector_irq
|
||||
vector_irq:
|
||||
stmfd sp!, {r0-r12,lr}
|
||||
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
@ if rt_thread_switch_interrupt_flag set, jump to
|
||||
@ rt_hw_context_switch_interrupt_do and don't return
|
||||
ldr r0, =rt_thread_switch_interrupt_flag
|
||||
ldr r1, [r0]
|
||||
cmp r1, #1
|
||||
beq rt_hw_context_switch_interrupt_do
|
||||
|
||||
ldmfd sp!, {r0-r12,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
mov r1, #0 @ clear flag
|
||||
str r1, [r0]
|
||||
|
||||
ldmfd sp!, {r0-r12,lr}@ reload saved registers
|
||||
stmfd sp, {r0-r2} @ save r0-r2
|
||||
|
||||
mrs r0, spsr @ get cpsr of interrupt thread
|
||||
|
||||
sub r1, sp, #4*3
|
||||
sub r2, lr, #4 @ save old task's pc to r2
|
||||
|
||||
@ switch to SVC mode with no interrupt
|
||||
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
|
||||
|
||||
stmfd sp!, {r2} @ push old task's pc
|
||||
stmfd sp!, {r3-r12,lr}@ push old task's lr,r12-r4
|
||||
ldmfd r1, {r1-r3} @ restore r0-r2 of the interrupt thread
|
||||
stmfd sp!, {r1-r3} @ push old task's r0-r2
|
||||
stmfd sp!, {r0} @ push old task's cpsr
|
||||
|
||||
ldr r4, =rt_interrupt_from_thread
|
||||
ldr r5, [r4]
|
||||
str sp, [r5] @ store sp in preempted tasks's TCB
|
||||
|
||||
ldr r6, =rt_interrupt_to_thread
|
||||
ldr r6, [r6]
|
||||
ldr sp, [r6] @ get new task's stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task's cpsr to spsr
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-04-06 zchong the first version
|
||||
*/
|
||||
|
||||
MODULE ?cstartup
|
||||
|
||||
; --------------------
|
||||
; Mode, correspords to bits 0-5 in CPSR
|
||||
|
||||
MODE_MSK DEFINE 0x1F ; Bit mask for mode bits in CPSR
|
||||
I_Bit DEFINE 0x80 ; when I bit is set, IRQ is disabled
|
||||
F_Bit DEFINE 0x40 ; when F bit is set, FIQ is disabled
|
||||
|
||||
USR_MODE DEFINE 0x10 ; User mode
|
||||
FIQ_MODE DEFINE 0x11 ; Fast Interrupt Request mode
|
||||
IRQ_MODE DEFINE 0x12 ; Interrupt Request mode
|
||||
SVC_MODE DEFINE 0x13 ; Supervisor mode
|
||||
ABT_MODE DEFINE 0x17 ; Abort mode
|
||||
UND_MODE DEFINE 0x1B ; Undefined Instruction mode
|
||||
SYS_MODE DEFINE 0x1F ; System mode
|
||||
|
||||
|
||||
;; Forward declaration of sections.
|
||||
SECTION IRQ_STACK:DATA:NOROOT(3)
|
||||
SECTION FIQ_STACK:DATA:NOROOT(3)
|
||||
SECTION SVC_STACK:DATA:NOROOT(3)
|
||||
SECTION ABT_STACK:DATA:NOROOT(3)
|
||||
SECTION UND_STACK:DATA:NOROOT(3)
|
||||
SECTION CSTACK:DATA:NOROOT(3)
|
||||
SECTION .text:CODE
|
||||
|
||||
|
||||
SECTION .intvec:CODE:NOROOT(5)
|
||||
|
||||
PUBLIC __vector
|
||||
PUBLIC __iar_program_start
|
||||
|
||||
|
||||
__iar_init$$done: ; The vector table is not needed
|
||||
; until after copy initialization is done
|
||||
|
||||
__vector: ; Make this a DATA label, so that stack usage
|
||||
; analysis doesn't consider it an uncalled fun
|
||||
ARM
|
||||
|
||||
; All default exception handlers (except reset) are
|
||||
; defined as weak symbol definitions.
|
||||
; If a handler is defined by the application it will take precedence.
|
||||
LDR PC,Reset_Addr ; Reset
|
||||
LDR PC,Undefined_Addr ; Undefined instructions
|
||||
LDR PC,SWI_Addr ; Software interrupt (SWI/SVC)
|
||||
LDR PC,Prefetch_Addr ; Prefetch abort
|
||||
LDR PC,Abort_Addr ; Data abort
|
||||
DCD 0 ; RESERVED
|
||||
LDR PC,IRQ_Addr ; IRQ
|
||||
LDR PC,FIQ_Addr ; FIQ
|
||||
|
||||
DATA
|
||||
|
||||
Reset_Addr: DCD __iar_program_start
|
||||
Undefined_Addr: DCD Undefined_Handler
|
||||
SWI_Addr: DCD SWI_Handler
|
||||
Prefetch_Addr: DCD Prefetch_Handler
|
||||
Abort_Addr: DCD Abort_Handler
|
||||
IRQ_Addr: DCD IRQ_Handler
|
||||
FIQ_Addr: DCD FIQ_Handler
|
||||
|
||||
|
||||
; --------------------------------------------------
|
||||
; ?cstartup -- low-level system initialization code.
|
||||
;
|
||||
; After a reset execution starts here, the mode is ARM, supervisor
|
||||
; with interrupts disabled.
|
||||
;
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
EXTERN rt_hw_trap_udef
|
||||
EXTERN rt_hw_trap_swi
|
||||
EXTERN rt_hw_trap_pabt
|
||||
EXTERN rt_hw_trap_dabt
|
||||
EXTERN rt_hw_trap_fiq
|
||||
EXTERN rt_hw_trap_irq
|
||||
EXTERN rt_interrupt_enter
|
||||
EXTERN rt_interrupt_leave
|
||||
EXTERN rt_thread_switch_interrupt_flag
|
||||
EXTERN rt_interrupt_from_thread
|
||||
EXTERN rt_interrupt_to_thread
|
||||
EXTERN rt_current_thread
|
||||
EXTERN vmm_thread
|
||||
EXTERN vmm_virq_check
|
||||
|
||||
EXTERN __cmain
|
||||
REQUIRE __vector
|
||||
EXTWEAK __iar_init_core
|
||||
EXTWEAK __iar_init_vfp
|
||||
|
||||
|
||||
ARM
|
||||
|
||||
__iar_program_start:
|
||||
?cstartup:
|
||||
|
||||
;
|
||||
; Add initialization needed before setup of stackpointers here.
|
||||
;
|
||||
|
||||
;
|
||||
; Initialize the stack pointers.
|
||||
; The pattern below can be used for any of the exception stacks:
|
||||
; FIQ, IRQ, SVC, ABT, UND, SYS.
|
||||
; The USR mode uses the same stack as SYS.
|
||||
; The stack segments must be defined in the linker command file,
|
||||
; and be declared above.
|
||||
;
|
||||
|
||||
MRS r0, cpsr ; Original PSR value
|
||||
|
||||
;; Set up the interrupt stack pointer.
|
||||
BIC r0, r0, #MODE_MSK ; Clear the mode bits
|
||||
ORR r0, r0, #IRQ_MODE ; Set IRQ mode bits
|
||||
MSR cpsr_c, r0 ; Change the mode
|
||||
LDR sp, =SFE(IRQ_STACK) ; End of IRQ_STACK
|
||||
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Set up the fast interrupt stack pointer.
|
||||
BIC r0, r0, #MODE_MSK ; Clear the mode bits
|
||||
ORR r0, r0, #FIQ_MODE ; Set FIR mode bits
|
||||
MSR cpsr_c, r0 ; Change the mode
|
||||
LDR sp, =SFE(FIQ_STACK) ; End of FIQ_STACK
|
||||
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
BIC r0,r0,#MODE_MSK ; Clear the mode bits
|
||||
ORR r0,r0,#ABT_MODE ; Set Abort mode bits
|
||||
MSR cpsr_c,r0 ; Change the mode
|
||||
LDR sp,=SFE(ABT_STACK) ; End of ABT_STACK
|
||||
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
BIC r0,r0,#MODE_MSK ; Clear the mode bits
|
||||
ORR r0,r0,#UND_MODE ; Set Undefined mode bits
|
||||
MSR cpsr_c,r0 ; Change the mode
|
||||
LDR sp,=SFE(UND_STACK) ; End of UND_STACK
|
||||
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Set up the normal stack pointer.
|
||||
BIC r0 ,r0, #MODE_MSK ; Clear the mode bits
|
||||
ORR r0 ,r0, #SVC_MODE ; Set System mode bits
|
||||
MSR cpsr_c, r0 ; Change the mode
|
||||
LDR sp, =SFE(SVC_STACK) ; End of SVC_STACK
|
||||
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Turn on core features assumed to be enabled.
|
||||
BL __iar_init_core
|
||||
|
||||
;; Initialize VFP (if needed).
|
||||
BL __iar_init_vfp
|
||||
|
||||
|
||||
;; Continue to __cmain for C-level initialization.
|
||||
B __cmain
|
||||
|
||||
|
||||
Undefined_Handler:
|
||||
SUB sp, sp, #72
|
||||
STMIA sp, {r0 - r12} ;/* Calling r0-r12 */
|
||||
ADD r8, sp, #60
|
||||
|
||||
MRS r1, cpsr
|
||||
MRS r2, spsr
|
||||
ORR r2,r2, #I_Bit | F_Bit
|
||||
MSR cpsr_c, r2
|
||||
MOV r0, r0
|
||||
STMDB r8, {sp, lr} ;/* Calling SP, LR */
|
||||
MSR cpsr_c, r1 ;/* return to Undefined Instruction mode */
|
||||
|
||||
STR lr, [r8, #0] ;/* Save calling PC */
|
||||
MRS r6, spsr
|
||||
STR r6, [r8, #4] ;/* Save CPSR */
|
||||
STR r0, [r8, #8] ;/* Save OLD_R0 */
|
||||
MOV r0, sp
|
||||
|
||||
BL rt_hw_trap_udef
|
||||
|
||||
LDMIA sp, {r0 - r12} ;/* Calling r0 - r2 */
|
||||
MOV r0, r0
|
||||
LDR lr, [sp, #60] ;/* Get PC */
|
||||
ADD sp, sp, #72
|
||||
MOVS pc, lr ;/* return & move spsr_svc into cpsr */
|
||||
|
||||
SWI_Handler:
|
||||
BL rt_hw_trap_swi
|
||||
|
||||
Prefetch_Handler:
|
||||
BL rt_hw_trap_pabt
|
||||
|
||||
Abort_Handler:
|
||||
SUB sp, sp, #72
|
||||
STMIA sp, {r0 - r12} ;/* Calling r0-r12 */
|
||||
ADD r8, sp, #60
|
||||
STMDB r8, {sp, lr} ;/* Calling SP, LR */
|
||||
STR lr, [r8, #0] ;/* Save calling PC */
|
||||
MRS r6, spsr
|
||||
STR r6, [r8, #4] ;/* Save CPSR */
|
||||
STR r0, [r8, #8] ;/* Save OLD_R0 */
|
||||
MOV r0, sp
|
||||
|
||||
BL rt_hw_trap_dabt
|
||||
|
||||
LDMIA sp, {r0 - r12} ;/* Calling r0 - r2 */
|
||||
MOV r0, r0
|
||||
LDR lr, [sp, #60] ;/* Get PC */
|
||||
ADD sp, sp, #72
|
||||
MOVS pc, lr ;/* return & move spsr_svc into cpsr */
|
||||
|
||||
FIQ_Handler:
|
||||
STMFD sp!,{r0-r7,lr}
|
||||
BL rt_hw_trap_fiq
|
||||
LDMFD sp!,{r0-r7,lr}
|
||||
SUBS pc,lr,#4
|
||||
|
||||
IRQ_Handler:
|
||||
STMFD sp!, {r0-r12,lr}
|
||||
|
||||
BL rt_interrupt_enter
|
||||
BL rt_hw_trap_irq
|
||||
BL rt_interrupt_leave
|
||||
|
||||
; if rt_thread_switch_interrupt_flag set, jump to
|
||||
; rt_hw_context_switch_interrupt_do and don't return
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #1
|
||||
BEQ rt_hw_context_switch_interrupt_do
|
||||
|
||||
LDMFD sp!, {r0-r12,lr}
|
||||
SUBS pc, lr, #4
|
||||
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
MOV r1, #0 ; clear flag
|
||||
STR r1, [r0]
|
||||
|
||||
LDMFD sp!, {r0-r12,lr}; reload saved registers
|
||||
STMFD sp, {r0-r2} ; save r0-r2
|
||||
|
||||
MRS r0, spsr ; get cpsr of interrupt thread
|
||||
|
||||
SUB r1, sp, #4*3
|
||||
SUB r2, lr, #4 ; save old task's pc to r2
|
||||
|
||||
; switch to SVC mode with no interrupt
|
||||
MSR cpsr_c, #I_Bit | F_Bit | SVC_MODE
|
||||
|
||||
STMFD sp!, {r2} ; push old task's pc
|
||||
STMFD sp!, {r3-r12,lr}; push old task's lr,r12-r4
|
||||
LDMFD r1, {r1-r3} ; restore r0-r2 of the interrupt thread
|
||||
STMFD sp!, {r1-r3} ; push old task's r0-r2
|
||||
STMFD sp!, {r0} ; push old task's cpsr
|
||||
|
||||
LDR r4, =rt_interrupt_from_thread
|
||||
LDR r5, [r4]
|
||||
STR sp, [r5] ; store sp in preempted tasks's TCB
|
||||
|
||||
LDR r6, =rt_interrupt_to_thread
|
||||
LDR r6, [r6]
|
||||
LDR sp, [r6] ; get new task's stack pointer
|
||||
|
||||
LDMFD sp!, {r4} ; pop new task's cpsr to spsr
|
||||
MSR spsr_cxsf, r4
|
||||
|
||||
LDMFD sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr
|
||||
|
||||
END
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-23 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#include "am33xx.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#ifdef RT_USING_GDB
|
||||
#include "gdb_stub.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup AM33XX
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
extern struct rt_thread *rt_current_thread;
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* this function will show registers of CPU
|
||||
*
|
||||
* @param regs the registers point
|
||||
*/
|
||||
|
||||
void rt_hw_show_register (struct rt_hw_register *regs)
|
||||
{
|
||||
rt_kprintf("Execption:\n");
|
||||
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10);
|
||||
rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip);
|
||||
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc);
|
||||
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
|
||||
}
|
||||
|
||||
/**
|
||||
* When ARM7TDMI comes across an instruction which it cannot handle,
|
||||
* it takes the undefined instruction trap.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_udef(struct rt_hw_register *regs)
|
||||
{
|
||||
|
||||
#ifdef RT_USING_GDB
|
||||
regs->pc -= 4; //lr in undef is pc + 4
|
||||
if (gdb_undef_hook(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("undefined instruction\n");
|
||||
rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The software interrupt instruction (SWI) is used for entering
|
||||
* Supervisor mode, usually to request a particular supervisor
|
||||
* function.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_swi(struct rt_hw_register *regs)
|
||||
{
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("software interrupt\n");
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during an instruction prefetch.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_pabt(struct rt_hw_register *regs)
|
||||
{
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("prefetch abort\n");
|
||||
rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during a data access.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_dabt(struct rt_hw_register *regs)
|
||||
{
|
||||
|
||||
#ifdef RT_USING_GDB
|
||||
if (gdb_mem_fault_handler) {
|
||||
regs->pc = (unsigned long)gdb_mem_fault_handler;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("data abort\n");
|
||||
rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
void rt_hw_trap_irq()
|
||||
{
|
||||
void *param;
|
||||
unsigned long ir;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
ir = rt_hw_interrupt_get_active(INT_IRQ);
|
||||
if (ir == 127)
|
||||
{
|
||||
/* new IRQ generation */
|
||||
rt_hw_interrupt_ack(INT_IRQ);
|
||||
ir = rt_hw_interrupt_get_active(INT_IRQ);
|
||||
if (ir == 127)
|
||||
{
|
||||
/* still spurious interrupt, get out */
|
||||
/*rt_kprintf("still spurious interrupt\n");*/
|
||||
return;
|
||||
}
|
||||
/*rt_kprintf("new IRQ: %d\n", ir);*/
|
||||
}
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir].handler;
|
||||
param = isr_table[ir].param;
|
||||
|
||||
/* turn to interrupt service routine */
|
||||
if (isr_func != RT_NULL)
|
||||
isr_func(ir, param);
|
||||
|
||||
/* new IRQ generation */
|
||||
rt_hw_interrupt_ack(INT_IRQ);
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq()
|
||||
{
|
||||
void *param;
|
||||
unsigned long ir;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
ir = rt_hw_interrupt_get_active(INT_FIQ);
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir].handler;
|
||||
param = isr_table[ir].param;
|
||||
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(ir, param);
|
||||
|
||||
/* new FIQ generation */
|
||||
rt_hw_interrupt_ack(INT_FIQ);
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
.section .vectors, "ax"
|
||||
.code 32
|
||||
|
||||
.globl system_vectors
|
||||
system_vectors:
|
||||
ldr pc, _vector_reset
|
||||
ldr pc, _vector_undef
|
||||
ldr pc, _vector_swi
|
||||
ldr pc, _vector_pabt
|
||||
ldr pc, _vector_dabt
|
||||
ldr pc, _vector_resv
|
||||
ldr pc, _vector_irq
|
||||
ldr pc, _vector_fiq
|
||||
|
||||
.globl _reset
|
||||
.globl vector_undef
|
||||
.globl vector_swi
|
||||
.globl vector_pabt
|
||||
.globl vector_dabt
|
||||
.globl vector_resv
|
||||
.globl vector_irq
|
||||
.globl vector_fiq
|
||||
|
||||
_vector_reset:
|
||||
.word _reset
|
||||
_vector_undef:
|
||||
.word vector_undef
|
||||
_vector_swi:
|
||||
.word vector_swi
|
||||
_vector_pabt:
|
||||
.word vector_pabt
|
||||
_vector_dabt:
|
||||
.word vector_dabt
|
||||
_vector_resv:
|
||||
.word vector_resv
|
||||
_vector_irq:
|
||||
.word vector_irq
|
||||
_vector_fiq:
|
||||
.word vector_fiq
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
@@ -0,0 +1,25 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
ASFLAGS = ''
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
ASFLAGS = ' --cpreproc'
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,79 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-08-14 weety copy from mini2440
|
||||
; */
|
||||
|
||||
#define NOINT 0xC0
|
||||
|
||||
.text
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, CPSR
|
||||
ORR R1, R0, #NOINT
|
||||
MSR CPSR_c, R1
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR CPSR, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
STMFD SP!, {LR} @; push pc (lr should be pushed in place of pc)
|
||||
STMFD SP!, {R0-R12, LR} @; push lr & register file
|
||||
MRS R4, CPSR
|
||||
STMFD SP!, {R4} @; push cpsr
|
||||
STR SP, [R0] @; store sp in preempted tasks tcb
|
||||
LDR SP, [R1] @; get new task stack pointer
|
||||
LDMFD SP!, {R4} @; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR SP, [R0] @; get new task stack pointer
|
||||
LDMFD SP!, {R4} @; pop new task cpsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOV R3, #1 @; set flag to 1
|
||||
STR R3, [R2]
|
||||
LDR R2, =rt_interrupt_from_thread @; set rt_interrupt_from_thread
|
||||
STR R0, [R2]
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread @; set rt_interrupt_to_thread
|
||||
STR R1, [R2]
|
||||
BX LR
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-08-14 weety copy from mini2440
|
||||
* 2015-04-15 ArdaFu convert from context_gcc.s
|
||||
*/
|
||||
|
||||
#define NOINT 0xc0
|
||||
|
||||
SECTION .text:CODE(6)
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
PUBLIC rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, CPSR
|
||||
ORR R1, R0, #NOINT
|
||||
MSR CPSR_C, R1
|
||||
MOV PC, LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
PUBLIC rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR CPSR_CXSF, R0
|
||||
MOV PC, LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
PUBLIC rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
STMFD SP!, {LR} ; push pc (lr should be pushed in place of PC)
|
||||
STMFD SP!, {R0-R12, LR} ; push lr & register file
|
||||
MRS R4, CPSR
|
||||
STMFD SP!, {R4} ; push cpsr
|
||||
STR SP, [R0] ; store sp in preempted tasks TCB
|
||||
LDR SP, [R1] ; get new task stack pointer
|
||||
LDMFD SP!, {R4} ; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
PUBLIC rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR SP, [R0] ; get new task stack pointer
|
||||
LDMFD SP!, {R4} ; pop new task spsr
|
||||
MSR SPSR_cxsf, R4
|
||||
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
PUBLIC rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOV R3, #1 ; set flag to 1
|
||||
STR R3, [R2]
|
||||
LDR R2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR R0, [R2]
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR R1, [R2]
|
||||
MOV PC, LR
|
||||
END
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-08-14 weety copy from mini2440
|
||||
; */
|
||||
|
||||
NOINT EQU 0XC0 ; disable interrupt in psr
|
||||
|
||||
AREA |.TEXT|, CODE, READONLY, ALIGN=2
|
||||
ARM
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS R0, CPSR
|
||||
ORR R1, R0, #NOINT
|
||||
MSR CPSR_C, R1
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable proc
|
||||
export rt_hw_interrupt_enable
|
||||
msr cpsr_c, r0
|
||||
bx lr
|
||||
endp
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch proc
|
||||
export rt_hw_context_switch
|
||||
stmfd sp!, {lr} ; push pc (lr should be pushed in place of pc)
|
||||
stmfd sp!, {r0-r12, lr} ; push lr & register file
|
||||
mrs r4, cpsr
|
||||
stmfd sp!, {r4} ; push cpsr
|
||||
str sp, [r0] ; store sp in preempted tasks tcb
|
||||
ldr sp, [r1] ; get new task stack pointer
|
||||
ldmfd sp!, {r4} ; pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc
|
||||
endp
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
rt_hw_context_switch_to proc
|
||||
export rt_hw_context_switch_to
|
||||
ldr sp, [r0] ; get new task stack pointer
|
||||
ldmfd sp!, {r4} ; pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc
|
||||
endp
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
; */
|
||||
import rt_thread_switch_interrupt_flag
|
||||
import rt_interrupt_from_thread
|
||||
import rt_interrupt_to_thread
|
||||
|
||||
rt_hw_context_switch_interrupt proc
|
||||
export rt_hw_context_switch_interrupt
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
mov r3, #1 ; set flag to 1
|
||||
str r3, [r2]
|
||||
ldr r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
str r0, [r2]
|
||||
_reswitch
|
||||
ldr r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
endp
|
||||
|
||||
end
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety modified from mini2440
|
||||
* 2015-04-15 ArdaFu Add code for IAR
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
|
||||
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
|
||||
|
||||
extern void machine_reset(void);
|
||||
extern void machine_shutdown(void);
|
||||
|
||||
#if defined(__GNUC__) || defined(__ICCARM__)
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
__asm volatile("mrc p15, 0, %0, c1, c0, 0":"=r"(i));
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
__asm volatile(\
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"orr r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
: "r"(bit) \
|
||||
: "memory");
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
__asm volatile(\
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"bic r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
: "r"(bit) \
|
||||
: "memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, i, c1, c0, 0
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_enable()
|
||||
{
|
||||
cache_enable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_disable()
|
||||
{
|
||||
cache_disable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of I-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_icache_status()
|
||||
{
|
||||
return (cp15_rd() & ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* enable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_enable()
|
||||
{
|
||||
cache_enable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_disable()
|
||||
{
|
||||
cache_disable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of D-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_dcache_status()
|
||||
{
|
||||
return (cp15_rd() & DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset cpu by dog's time-out
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset()
|
||||
{
|
||||
|
||||
rt_kprintf("Restarting system...\n");
|
||||
machine_reset();
|
||||
|
||||
while (1); /* loop forever and wait for reset to happen */
|
||||
|
||||
/* NEVER REACHED */
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
machine_shutdown();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
register rt_uint32_t x;
|
||||
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
__asm
|
||||
{
|
||||
rsb x, value, #0
|
||||
and x, x, value
|
||||
clz x, x
|
||||
rsb x, x, #32
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
#elif defined(__GNUC__) || defined(__ICCARM__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-02-08 RT-Thread the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
RT_WEAK void machine_reset(void)
|
||||
{
|
||||
rt_kprintf("reboot system...\n");
|
||||
rt_hw_interrupt_disable();
|
||||
while (1);
|
||||
}
|
||||
|
||||
RT_WEAK void machine_shutdown(void)
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
rt_hw_interrupt_disable();
|
||||
while (1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-04-15 ArdaFu Add code for IAR
|
||||
*/
|
||||
|
||||
#include "mmu.h"
|
||||
|
||||
/*----- Keil -----------------------------------------------------------------*/
|
||||
#ifdef __CC_ARM
|
||||
void mmu_setttbase(rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
__asm volatile{ mcr p15, 0, value, c8, c7, 0 }
|
||||
value = 0x55555555;
|
||||
__asm volatile { mcr p15, 0, value, c3, c0, 0 }
|
||||
__asm volatile { mcr p15, 0, i, c2, c0, 0 }
|
||||
}
|
||||
|
||||
void mmu_set_domain(rt_uint32_t i)
|
||||
{
|
||||
__asm volatile { mcr p15, 0, i, c3, c0, 0 }
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
__asm volatile { mcr p15, 0, index, c7, c14, 2 }
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile { MCR p15, 0, ptr, c7, c14, 1 }
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile { MCR p15, 0, ptr, c7, c10, 1 }
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile { MCR p15, 0, ptr, c7, c6, 1 }
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
__asm volatile { mcr p15, 0, value, c8, c7, 0 }
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile { mcr p15, 0, value, c7, c5, 0 }
|
||||
}
|
||||
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile { mcr p15, 0, value, c7, c6, 0 }
|
||||
}
|
||||
/*----- GNU ------------------------------------------------------------------*/
|
||||
#elif defined(__GNUC__) || defined(__ICCARM__)
|
||||
void mmu_setttbase(register rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
asm volatile("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
|
||||
|
||||
value = 0x55555555;
|
||||
asm volatile("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
|
||||
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
|
||||
|
||||
}
|
||||
|
||||
void mmu_set_domain(register rt_uint32_t i)
|
||||
{
|
||||
asm volatile("mcr p15,0, %0, c3, c0, 0": :"r"(i));
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #0x1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #0x1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #(1<<12) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #(1<<2) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #(1<<12) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #(1<<2) \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"orr r0, r0, #1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
asm volatile
|
||||
(
|
||||
"mrc p15, 0, r0, c1, c0, 0 \n"
|
||||
"bic r0, r0, #1 \n"
|
||||
"mcr p15, 0, r0, c1, c0, 0 \n"
|
||||
:::"r0"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c14, 2": :"r"(index));
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c14, 1": :"r"(ptr));
|
||||
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c10, 1": :"r"(ptr));
|
||||
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c6, 1": :"r"(ptr));
|
||||
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c8, c7, 0": :"r"(0));
|
||||
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c5, 0": :"r"(0));
|
||||
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
asm volatile("mcr p15, 0, %0, c7, c6, 0": :"r"(0));
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* level1 page table */
|
||||
#if defined(__ICCARM__)
|
||||
#pragma data_alignment=(16*1024)
|
||||
static volatile rt_uint32_t _page_table[4 * 1024];
|
||||
#else
|
||||
static volatile rt_uint32_t _page_table[4 * 1024] \
|
||||
__attribute__((aligned(16 * 1024)));
|
||||
#endif
|
||||
|
||||
void mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd,
|
||||
rt_uint32_t paddrStart, rt_uint32_t attr)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile int nSec;
|
||||
int i = 0;
|
||||
pTT = (rt_uint32_t *)_page_table + (vaddrStart >> 20);
|
||||
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
|
||||
for (i = 0; i <= nSec; i++)
|
||||
{
|
||||
*pTT = attr | (((paddrStart >> 20) + i) << 20);
|
||||
pTT++;
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
/* disable I/D cache */
|
||||
mmu_disable_dcache();
|
||||
mmu_disable_icache();
|
||||
mmu_disable();
|
||||
mmu_invalidate_tlb();
|
||||
|
||||
/* set page table */
|
||||
for (; size > 0; size--)
|
||||
{
|
||||
mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
|
||||
mdesc->paddr_start, mdesc->attr);
|
||||
mdesc++;
|
||||
}
|
||||
|
||||
/* set MMU table address */
|
||||
mmu_setttbase((rt_uint32_t)_page_table);
|
||||
|
||||
/* enables MMU */
|
||||
mmu_enable();
|
||||
|
||||
/* enable Instruction Cache */
|
||||
mmu_enable_icache();
|
||||
|
||||
/* enable Data Cache */
|
||||
mmu_enable_dcache();
|
||||
|
||||
mmu_invalidate_icache();
|
||||
mmu_invalidate_dcache_all();
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-02-08 RT-Thread the first version
|
||||
*/
|
||||
|
||||
#ifndef __MMU_H__
|
||||
#define __MMU_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define CACHE_LINE_SIZE 32
|
||||
|
||||
#define DESC_SEC (0x2|(1<<4))
|
||||
#define CB (3<<2) //cache_on, write_back
|
||||
#define CNB (2<<2) //cache_on, write_through
|
||||
#define NCB (1<<2) //cache_off,WR_BUF on
|
||||
#define NCNB (0<<2) //cache_off,WR_BUF off
|
||||
#define AP_RW (3<<10) //supervisor=RW, user=RW
|
||||
#define AP_RO (2<<10) //supervisor=RW, user=RO
|
||||
|
||||
#define DOMAIN_FAULT (0x0)
|
||||
#define DOMAIN_CHK (0x1)
|
||||
#define DOMAIN_NOTCHK (0x3)
|
||||
#define DOMAIN0 (0x0<<5)
|
||||
#define DOMAIN1 (0x1<<5)
|
||||
|
||||
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
|
||||
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
|
||||
|
||||
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
|
||||
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
|
||||
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
|
||||
struct mem_desc
|
||||
{
|
||||
rt_uint32_t vaddr_start;
|
||||
rt_uint32_t vaddr_end;
|
||||
rt_uint32_t paddr_start;
|
||||
rt_uint32_t attr;
|
||||
};
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size);
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size);
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size);
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety copy from mini2440
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
/*****************************/
|
||||
/* CPU Mode */
|
||||
/*****************************/
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety first version
|
||||
* 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
|
||||
* 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table
|
||||
* 2015-06-04 aozima Align stack address to 8 byte.
|
||||
*/
|
||||
|
||||
.equ MODE_USR, 0x10
|
||||
.equ MODE_FIQ, 0x11
|
||||
.equ MODE_IRQ, 0x12
|
||||
.equ MODE_SVC, 0x13
|
||||
.equ MODE_ABT, 0x17
|
||||
.equ MODE_UND, 0x1B
|
||||
.equ MODE_SYS, 0x1F
|
||||
.equ MODEMASK, 0x1F
|
||||
.equ NOINT, 0xC0
|
||||
|
||||
.equ I_BIT, 0x80
|
||||
.equ F_BIT, 0x40
|
||||
|
||||
.equ UND_STACK_SIZE, 0x00000100
|
||||
.equ SVC_STACK_SIZE, 0x00000100
|
||||
.equ ABT_STACK_SIZE, 0x00000100
|
||||
.equ FIQ_STACK_SIZE, 0x00000100
|
||||
.equ IRQ_STACK_SIZE, 0x00000100
|
||||
.equ SYS_STACK_SIZE, 0x00000100
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* Interrupt vector table
|
||||
***************************************
|
||||
*/
|
||||
.section .vectors
|
||||
.code 32
|
||||
|
||||
.global system_vectors
|
||||
system_vectors:
|
||||
ldr pc, _vector_reset
|
||||
ldr pc, _vector_undef
|
||||
ldr pc, _vector_swi
|
||||
ldr pc, _vector_pabt
|
||||
ldr pc, _vector_dabt
|
||||
ldr pc, _vector_resv
|
||||
ldr pc, _vector_irq
|
||||
ldr pc, _vector_fiq
|
||||
|
||||
_vector_reset:
|
||||
.word reset
|
||||
_vector_undef:
|
||||
.word vector_undef
|
||||
_vector_swi:
|
||||
.word vector_swi
|
||||
_vector_pabt:
|
||||
.word vector_pabt
|
||||
_vector_dabt:
|
||||
.word vector_dabt
|
||||
_vector_resv:
|
||||
.word vector_resv
|
||||
_vector_irq:
|
||||
.word vector_irq
|
||||
_vector_fiq:
|
||||
.word vector_fiq
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* Stack and Heap Definitions
|
||||
***************************************
|
||||
*/
|
||||
.section .data
|
||||
.space UND_STACK_SIZE
|
||||
.align 3
|
||||
.global und_stack_start
|
||||
und_stack_start:
|
||||
|
||||
.space ABT_STACK_SIZE
|
||||
.align 3
|
||||
.global abt_stack_start
|
||||
abt_stack_start:
|
||||
|
||||
.space FIQ_STACK_SIZE
|
||||
.align 3
|
||||
.global fiq_stack_start
|
||||
fiq_stack_start:
|
||||
|
||||
.space IRQ_STACK_SIZE
|
||||
.align 3
|
||||
.global irq_stack_start
|
||||
irq_stack_start:
|
||||
|
||||
.skip SYS_STACK_SIZE
|
||||
.align 3
|
||||
.global sys_stack_start
|
||||
sys_stack_start:
|
||||
|
||||
.space SVC_STACK_SIZE
|
||||
.align 3
|
||||
.global svc_stack_start
|
||||
svc_stack_start:
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* Startup Code
|
||||
***************************************
|
||||
*/
|
||||
.section .text
|
||||
.global reset
|
||||
reset:
|
||||
/* Enter svc mode and mask interrupts */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #MODEMASK
|
||||
orr r0, r0, #MODE_SVC|NOINT
|
||||
msr cpsr_cxsf, r0
|
||||
|
||||
/* init cpu */
|
||||
bl cpu_init_crit
|
||||
|
||||
/* Call low level init function */
|
||||
ldr sp, =svc_stack_start
|
||||
ldr r0, =rt_low_level_init
|
||||
blx r0
|
||||
|
||||
/* init stack */
|
||||
bl stack_setup
|
||||
|
||||
/* clear bss */
|
||||
mov r0, #0
|
||||
ldr r1, =__bss_start
|
||||
ldr r2, =__bss_end
|
||||
|
||||
bss_clear_loop:
|
||||
cmp r1, r2
|
||||
strlo r0, [r1], #4
|
||||
blo bss_clear_loop
|
||||
|
||||
/* call c++ constructors of global objects */
|
||||
/*
|
||||
ldr r0, =__ctors_start__
|
||||
ldr r1, =__ctors_end__
|
||||
|
||||
ctor_loop:
|
||||
cmp r0, r1
|
||||
beq ctor_end
|
||||
ldr r2, [r0], #4
|
||||
stmfd sp!, {r0-r1}
|
||||
mov lr, pc
|
||||
bx r2
|
||||
ldmfd sp!, {r0-r1}
|
||||
b ctor_loop
|
||||
ctor_end:
|
||||
*/
|
||||
/* start RT-Thread Kernel */
|
||||
ldr pc, _rtthread_startup
|
||||
_rtthread_startup:
|
||||
.word rtthread_startup
|
||||
|
||||
|
||||
|
||||
cpu_init_crit:
|
||||
/* invalidate I/D caches */
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c7, 0
|
||||
mcr p15, 0, r0, c8, c7, 0
|
||||
|
||||
/* disable MMU stuff and caches */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, r0, #0x00002300
|
||||
bic r0, r0, #0x00000087
|
||||
orr r0, r0, #0x00000002
|
||||
orr r0, r0, #0x00001000
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
bx lr
|
||||
|
||||
stack_setup:
|
||||
/* Setup Stack for each mode */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #MODEMASK
|
||||
|
||||
orr r1, r0, #MODE_UND|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =und_stack_start
|
||||
|
||||
orr r1, r0, #MODE_ABT|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =abt_stack_start
|
||||
|
||||
orr r1, r0, #MODE_IRQ|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =irq_stack_start
|
||||
|
||||
orr r1, r0, #MODE_FIQ|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =fiq_stack_start
|
||||
|
||||
orr r1, r0, #MODE_SYS|NOINT
|
||||
msr cpsr_cxsf,r1
|
||||
ldr sp, =sys_stack_start
|
||||
|
||||
orr r1, r0, #MODE_SVC|NOINT
|
||||
msr cpsr_cxsf, r1
|
||||
ldr sp, =svc_stack_start
|
||||
|
||||
bx lr
|
||||
|
||||
/*
|
||||
***************************************
|
||||
* exception handlers
|
||||
***************************************
|
||||
*/
|
||||
/* Interrupt */
|
||||
vector_fiq:
|
||||
stmfd sp!,{r0-r7,lr}
|
||||
bl rt_hw_trap_fiq
|
||||
ldmfd sp!,{r0-r7,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
vector_irq:
|
||||
stmfd sp!, {r0-r12,lr}
|
||||
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
ldr r0, =rt_thread_switch_interrupt_flag
|
||||
ldr r1, [r0]
|
||||
cmp r1, #1
|
||||
beq rt_hw_context_switch_interrupt_do
|
||||
|
||||
ldmfd sp!, {r0-r12,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
mov r1, #0
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, sp
|
||||
add sp, sp, #4*4
|
||||
ldmfd sp!, {r4-r12,lr}
|
||||
mrs r0, spsr
|
||||
sub r2, lr, #4
|
||||
|
||||
msr cpsr_c, #I_BIT|F_BIT|MODE_SVC
|
||||
|
||||
stmfd sp!, {r2}
|
||||
stmfd sp!, {r4-r12,lr}
|
||||
ldmfd r1, {r1-r4}
|
||||
stmfd sp!, {r1-r4}
|
||||
stmfd sp!, {r0}
|
||||
|
||||
ldr r4, =rt_interrupt_from_thread
|
||||
ldr r5, [r4]
|
||||
str sp, [r5]
|
||||
|
||||
ldr r6, =rt_interrupt_to_thread
|
||||
ldr r6, [r6]
|
||||
ldr sp, [r6]
|
||||
|
||||
ldmfd sp!, {r4}
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12,lr,pc}^
|
||||
|
||||
/* Exception */
|
||||
.macro push_svc_reg
|
||||
sub sp, sp, #17 * 4
|
||||
stmia sp, {r0 - r12}
|
||||
mov r0, sp
|
||||
mrs r6, spsr
|
||||
str lr, [r0, #15*4]
|
||||
str r6, [r0, #16*4]
|
||||
str sp, [r0, #13*4]
|
||||
str lr, [r0, #14*4]
|
||||
.endm
|
||||
|
||||
vector_swi:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_swi
|
||||
b .
|
||||
|
||||
vector_undef:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_udef
|
||||
b .
|
||||
|
||||
vector_pabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_pabt
|
||||
b .
|
||||
|
||||
vector_dabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_dabt
|
||||
b .
|
||||
|
||||
vector_resv:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_resv
|
||||
b .
|
||||
@@ -0,0 +1,278 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-01-13 weety first version
|
||||
; * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
|
||||
; * 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table
|
||||
; * 2015-06-04 aozima Align stack address to 8 byte.
|
||||
; */
|
||||
|
||||
#include "rt_low_level_init.h"
|
||||
|
||||
#define S_FRAME_SIZE (18*4) ;72
|
||||
|
||||
;#define S_SPSR (17*4) ;SPSR
|
||||
;#define S_CPSR (16*4) ;CPSR
|
||||
#define S_PC (15*4) ;R15
|
||||
;#define S_LR (14*4) ;R14
|
||||
;#define S_SP (13*4) ;R13
|
||||
|
||||
;#define S_IP (12*4) ;R12
|
||||
;#define S_FP (11*4) ;R11
|
||||
;#define S_R10 (10*4)
|
||||
;#define S_R9 (9*4)
|
||||
;#define S_R8 (8*4)
|
||||
;#define S_R7 (7*4)
|
||||
;#define S_R6 (6*4)
|
||||
;#define S_R5 (5*4)
|
||||
;#define S_R4 (4*4)
|
||||
;#define S_R3 (3*4)
|
||||
;#define S_R2 (2*4)
|
||||
;#define S_R1 (1*4)
|
||||
;#define S_R0 (0*4)
|
||||
|
||||
#define MODE_SYS 0x1F
|
||||
#define MODE_FIQ 0x11
|
||||
#define MODE_IRQ 0x12
|
||||
#define MODE_SVC 0x13
|
||||
#define MODE_ABT 0x17
|
||||
#define MODE_UND 0x1B
|
||||
#define MODEMASK 0x1F
|
||||
|
||||
#define NOINT 0xC0
|
||||
|
||||
;----------------------- Stack and Heap Definitions ----------------------------
|
||||
MODULE ?cstartup
|
||||
SECTION .noinit:DATA:NOROOT(3)
|
||||
DATA
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 UND_STK_SIZE
|
||||
PUBLIC UND_STACK_START
|
||||
UND_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 ABT_STK_SIZE
|
||||
PUBLIC ABT_STACK_START
|
||||
ABT_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 FIQ_STK_SIZE
|
||||
PUBLIC FIQ_STACK_START
|
||||
FIQ_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 IRQ_STK_SIZE
|
||||
PUBLIC IRQ_STACK_START
|
||||
IRQ_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 SYS_STK_SIZE
|
||||
PUBLIC SYS_STACK_START
|
||||
SYS_STACK_START:
|
||||
|
||||
ALIGNRAM 3
|
||||
DS8 SVC_STK_SIZE
|
||||
PUBLIC SVC_STACK_START
|
||||
SVC_STACK_START:
|
||||
|
||||
;--------------Jump vector table------------------------------------------------
|
||||
SECTION .intvec:CODE:ROOT(2)
|
||||
ARM
|
||||
PUBLIC Entry_Point
|
||||
Entry_Point:
|
||||
__iar_init$$done: ; The interrupt vector is not needed
|
||||
; until after copy initialization is done
|
||||
LDR PC, vector_reset
|
||||
LDR PC, vector_undef
|
||||
LDR PC, vector_swi
|
||||
LDR PC, vector_pabt
|
||||
LDR PC, vector_dabt
|
||||
LDR PC, vector_resv
|
||||
LDR PC, vector_irq
|
||||
LDR PC, vector_fiq
|
||||
|
||||
vector_reset:
|
||||
DC32 Reset_Handler
|
||||
vector_undef:
|
||||
DC32 Undef_Handler
|
||||
vector_swi:
|
||||
DC32 SWI_Handler
|
||||
vector_pabt:
|
||||
DC32 PAbt_Handler
|
||||
vector_dabt:
|
||||
DC32 DAbt_Handler
|
||||
vector_resv:
|
||||
DC32 Resv_Handler
|
||||
vector_irq:
|
||||
DC32 IRQ_Handler
|
||||
vector_fiq:
|
||||
DC32 FIQ_Handler
|
||||
|
||||
;----------------- Reset Handler -----------------------------------------------
|
||||
EXTERN rt_low_level_init
|
||||
EXTERN ?main
|
||||
PUBLIC __iar_program_start
|
||||
__iar_program_start:
|
||||
Reset_Handler:
|
||||
; Set the cpu to SVC32 mode
|
||||
MRS R0, CPSR
|
||||
BIC R0, R0, #MODEMASK
|
||||
ORR R0, R0, #MODE_SVC|NOINT
|
||||
MSR CPSR_cxsf, R0
|
||||
|
||||
; Set CO-Processor
|
||||
; little-end,disbale I/D Cache MMU, vector table is 0x00000000
|
||||
MRC P15, 0, R0, C1, C0, 0 ; Read CP15
|
||||
LDR R1, =0x00003085 ; set clear bits
|
||||
BIC R0, R0, R1
|
||||
MCR P15, 0, R0, C1, C0, 0 ; Write CP15
|
||||
|
||||
; Call low level init function,
|
||||
; disable and clear all IRQs, Init MMU, Init interrupt controller, etc.
|
||||
LDR SP, =SVC_STACK_START
|
||||
LDR R0, =rt_low_level_init
|
||||
BLX R0
|
||||
|
||||
Setup_Stack:
|
||||
; Setup Stack for each mode
|
||||
MRS R0, CPSR
|
||||
BIC R0, R0, #MODEMASK
|
||||
|
||||
ORR R1, R0, #MODE_UND|NOINT
|
||||
MSR CPSR_cxsf, R1 ; Undef mode
|
||||
LDR SP, =UND_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_ABT|NOINT
|
||||
MSR CPSR_cxsf,R1 ; Abort mode
|
||||
LDR SP, =ABT_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_IRQ|NOINT
|
||||
MSR CPSR_cxsf,R1 ; IRQ mode
|
||||
LDR SP, =IRQ_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_FIQ|NOINT
|
||||
MSR CPSR_cxsf,R1 ; FIQ mode
|
||||
LDR SP, =FIQ_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_SYS|NOINT
|
||||
MSR CPSR_cxsf,R1 ; SYS/User mode
|
||||
LDR SP, =SYS_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_SVC|NOINT
|
||||
MSR CPSR_cxsf,R1 ; SVC mode
|
||||
LDR SP, =SVC_STACK_START
|
||||
|
||||
; Enter the C code
|
||||
LDR R0, =?main
|
||||
BLX R0
|
||||
|
||||
;----------------- Exception Handler -------------------------------------------
|
||||
IMPORT rt_hw_trap_udef
|
||||
IMPORT rt_hw_trap_swi
|
||||
IMPORT rt_hw_trap_pabt
|
||||
IMPORT rt_hw_trap_dabt
|
||||
IMPORT rt_hw_trap_resv
|
||||
IMPORT rt_hw_trap_irq
|
||||
IMPORT rt_hw_trap_fiq
|
||||
|
||||
IMPORT rt_interrupt_enter
|
||||
IMPORT rt_interrupt_leave
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
SECTION .text:CODE:ROOT(2)
|
||||
ARM
|
||||
Undef_Handler:
|
||||
SUB SP, SP, #S_FRAME_SIZE
|
||||
STMIA SP, {R0 - R12} ; Calling R0-R12
|
||||
ADD R8, SP, #S_PC
|
||||
STMDB R8, {SP, LR} ; Calling SP, LR
|
||||
STR LR, [R8, #0] ; Save calling PC
|
||||
MRS R6, SPSR
|
||||
STR R6, [R8, #4] ; Save CPSR
|
||||
STR R0, [R8, #8] ; Save SPSR
|
||||
MOV R0, SP
|
||||
BL rt_hw_trap_udef
|
||||
|
||||
SWI_Handler:
|
||||
BL rt_hw_trap_swi
|
||||
|
||||
PAbt_Handler:
|
||||
BL rt_hw_trap_pabt
|
||||
|
||||
DAbt_Handler:
|
||||
SUB SP, SP, #S_FRAME_SIZE
|
||||
STMIA SP, {R0 - R12} ; Calling R0-R12
|
||||
ADD R8, SP, #S_PC
|
||||
STMDB R8, {SP, LR} ; Calling SP, LR
|
||||
STR LR, [R8, #0] ; Save calling PC
|
||||
MRS R6, SPSR
|
||||
STR R6, [R8, #4] ; Save CPSR
|
||||
STR R0, [R8, #8] ; Save SPSR
|
||||
MOV R0, SP
|
||||
BL rt_hw_trap_dabt
|
||||
|
||||
Resv_Handler:
|
||||
BL rt_hw_trap_resv
|
||||
|
||||
IRQ_Handler:
|
||||
STMFD SP!, {R0-R12,LR}
|
||||
BL rt_interrupt_enter
|
||||
BL rt_hw_trap_irq
|
||||
BL rt_interrupt_leave
|
||||
|
||||
; If rt_thread_switch_interrupt_flag set,
|
||||
; jump to rt_hw_context_switch_interrupt_do and don't return
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CMP R1, #1
|
||||
BEQ rt_hw_context_switch_interrupt_do
|
||||
|
||||
LDMFD SP!, {R0-R12,LR}
|
||||
SUBS PC, LR, #4
|
||||
|
||||
FIQ_Handler:
|
||||
STMFD SP!, {R0-R7,LR}
|
||||
BL rt_hw_trap_fiq
|
||||
LDMFD SP!, {R0-R7,LR}
|
||||
SUBS PC, LR, #4
|
||||
|
||||
;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) -----------------
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
MOV R1, #0 ; Clear flag
|
||||
STR R1, [R0] ; Save to flag variable
|
||||
|
||||
LDMFD SP!, {R0-R12,LR} ; Reload saved registers
|
||||
STMFD SP, {R0-R2} ; Save R0-R2
|
||||
SUB R1, SP, #4*3 ; Save old task's SP to R1
|
||||
SUB R2, LR, #4 ; Save old task's PC to R2
|
||||
|
||||
MRS R0, SPSR ; Get CPSR of interrupt thread
|
||||
|
||||
MSR CPSR_c, #MODE_SVC|NOINT ; Switch to SVC mode and no interrupt
|
||||
|
||||
STMFD SP!, {R2} ; Push old task's PC
|
||||
STMFD SP!, {R3-R12,LR} ; Push old task's LR,R12-R3
|
||||
LDMFD R1, {R1-R3}
|
||||
STMFD SP!, {R1-R3} ; Push old task's R2-R0
|
||||
STMFD SP!, {R0} ; Push old task's CPSR
|
||||
|
||||
LDR R4, =rt_interrupt_from_thread
|
||||
LDR R5, [R4] ; R5 = stack ptr in old tasks's TCB
|
||||
STR SP, [R5] ; Store SP in preempted tasks's TCB
|
||||
|
||||
LDR R6, =rt_interrupt_to_thread
|
||||
LDR R6, [R6] ; R6 = stack ptr in new tasks's TCB
|
||||
LDR SP, [R6] ; Get new task's stack pointer
|
||||
|
||||
LDMFD SP!, {R4} ; Pop new task's SPSR
|
||||
MSR SPSR_cxsf, R4
|
||||
|
||||
LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's R0-R12,LR & PC SPSR to CPSR
|
||||
END
|
||||
@@ -0,0 +1,301 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2011-08-14 weety first version
|
||||
; * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
|
||||
; * 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table
|
||||
; * 2015-06-04 aozima Align stack address to 8 byte.
|
||||
; */
|
||||
|
||||
UND_STK_SIZE EQU 512
|
||||
SVC_STK_SIZE EQU 4096
|
||||
ABT_STK_SIZE EQU 512
|
||||
IRQ_STK_SIZE EQU 1024
|
||||
FIQ_STK_SIZE EQU 1024
|
||||
SYS_STK_SIZE EQU 512
|
||||
Heap_Size EQU 512
|
||||
|
||||
S_FRAME_SIZE EQU (18*4) ;72
|
||||
S_PC EQU (15*4) ;R15
|
||||
|
||||
MODE_USR EQU 0X10
|
||||
MODE_FIQ EQU 0X11
|
||||
MODE_IRQ EQU 0X12
|
||||
MODE_SVC EQU 0X13
|
||||
MODE_ABT EQU 0X17
|
||||
MODE_UND EQU 0X1B
|
||||
MODE_SYS EQU 0X1F
|
||||
MODEMASK EQU 0X1F
|
||||
|
||||
NOINT EQU 0xC0
|
||||
|
||||
;----------------------- Stack and Heap Definitions ----------------------------
|
||||
AREA STACK, NOINIT, READWRITE, ALIGN=3
|
||||
Stack_Mem
|
||||
|
||||
SPACE UND_STK_SIZE
|
||||
EXPORT UND_STACK_START
|
||||
UND_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE ABT_STK_SIZE
|
||||
EXPORT ABT_STACK_START
|
||||
ABT_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE FIQ_STK_SIZE
|
||||
EXPORT FIQ_STACK_START
|
||||
FIQ_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE IRQ_STK_SIZE
|
||||
EXPORT IRQ_STACK_START
|
||||
IRQ_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE SYS_STK_SIZE
|
||||
EXPORT SYS_STACK_START
|
||||
SYS_STACK_START
|
||||
|
||||
ALIGN 8
|
||||
SPACE SVC_STK_SIZE
|
||||
EXPORT SVC_STACK_START
|
||||
SVC_STACK_START
|
||||
Stack_Top
|
||||
__initial_sp
|
||||
|
||||
__heap_base
|
||||
Heap_Mem SPACE Heap_Size
|
||||
__heap_limit
|
||||
|
||||
PRESERVE8
|
||||
;--------------Jump vector table------------------------------------------------
|
||||
EXPORT Entry_Point
|
||||
AREA RESET, CODE, READONLY
|
||||
ARM
|
||||
Entry_Point
|
||||
LDR PC, vector_reset
|
||||
LDR PC, vector_undef
|
||||
LDR PC, vector_swi
|
||||
LDR PC, vector_pabt
|
||||
LDR PC, vector_dabt
|
||||
LDR PC, vector_resv
|
||||
LDR PC, vector_irq
|
||||
LDR PC, vector_fiq
|
||||
|
||||
vector_reset
|
||||
DCD Reset_Handler
|
||||
vector_undef
|
||||
DCD Undef_Handler
|
||||
vector_swi
|
||||
DCD SWI_Handler
|
||||
vector_pabt
|
||||
DCD PAbt_Handler
|
||||
vector_dabt
|
||||
DCD DAbt_Handler
|
||||
vector_resv
|
||||
DCD Resv_Handler
|
||||
vector_irq
|
||||
DCD IRQ_Handler
|
||||
vector_fiq
|
||||
DCD FIQ_Handler
|
||||
|
||||
;----------------- Reset Handler -----------------------------------------------
|
||||
IMPORT rt_low_level_init
|
||||
IMPORT __main
|
||||
EXPORT Reset_Handler
|
||||
Reset_Handler
|
||||
; set the cpu to SVC32 mode
|
||||
MRS R0,CPSR
|
||||
BIC R0,R0,#MODEMASK
|
||||
ORR R0,R0,#MODE_SVC:OR:NOINT
|
||||
MSR CPSR_cxsf,R0
|
||||
|
||||
; Set CO-Processor
|
||||
; little-end,disbale I/D Cache MMU, vector table is 0x00000000
|
||||
MRC p15, 0, R0, c1, c0, 0 ; Read CP15
|
||||
LDR R1, =0x00003085 ; set clear bits
|
||||
BIC R0, R0, R1
|
||||
MCR p15, 0, R0, c1, c0, 0 ; Write CP15
|
||||
|
||||
; Call low level init function,
|
||||
; disable and clear all IRQs, Init MMU, Init interrupt controller, etc.
|
||||
LDR SP, =SVC_STACK_START
|
||||
LDR R0, =rt_low_level_init
|
||||
BLX R0
|
||||
|
||||
Setup_Stack
|
||||
; Setup Stack for each mode
|
||||
MRS R0, CPSR
|
||||
BIC R0, R0, #MODEMASK
|
||||
|
||||
ORR R1, R0, #MODE_UND:OR:NOINT
|
||||
MSR CPSR_cxsf, R1 ; Undef mode
|
||||
LDR SP, =UND_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_ABT:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; Abort mode
|
||||
LDR SP, =ABT_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_IRQ:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; IRQ mode
|
||||
LDR SP, =IRQ_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_FIQ:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; FIQ mode
|
||||
LDR SP, =FIQ_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_SYS:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; SYS/User mode
|
||||
LDR SP, =SYS_STACK_START
|
||||
|
||||
ORR R1,R0,#MODE_SVC:OR:NOINT
|
||||
MSR CPSR_cxsf,R1 ; SVC mode
|
||||
LDR SP, =SVC_STACK_START
|
||||
|
||||
; Enter the C code
|
||||
LDR R0, =__main
|
||||
BLX R0
|
||||
|
||||
;----------------- Exception Handler -------------------------------------------
|
||||
IMPORT rt_hw_trap_udef
|
||||
IMPORT rt_hw_trap_swi
|
||||
IMPORT rt_hw_trap_pabt
|
||||
IMPORT rt_hw_trap_dabt
|
||||
IMPORT rt_hw_trap_resv
|
||||
IMPORT rt_hw_trap_irq
|
||||
IMPORT rt_hw_trap_fiq
|
||||
|
||||
IMPORT rt_interrupt_enter
|
||||
IMPORT rt_interrupt_leave
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
Undef_Handler PROC
|
||||
SUB SP, SP, #S_FRAME_SIZE
|
||||
STMIA SP, {R0 - R12} ; Calling R0-R12
|
||||
ADD R8, SP, #S_PC
|
||||
STMDB R8, {SP, LR} ; Calling SP, LR
|
||||
STR LR, [R8, #0] ; Save calling PC
|
||||
MRS R6, SPSR
|
||||
STR R6, [R8, #4] ; Save CPSR
|
||||
STR R0, [R8, #8] ; Save SPSR
|
||||
MOV R0, SP
|
||||
BL rt_hw_trap_udef
|
||||
ENDP
|
||||
|
||||
SWI_Handler PROC
|
||||
BL rt_hw_trap_swi
|
||||
ENDP
|
||||
|
||||
PAbt_Handler PROC
|
||||
BL rt_hw_trap_pabt
|
||||
ENDP
|
||||
|
||||
DAbt_Handler PROC
|
||||
SUB SP, SP, #S_FRAME_SIZE
|
||||
STMIA SP, {R0 - R12} ; Calling R0-R12
|
||||
ADD R8, SP, #S_PC
|
||||
STMDB R8, {SP, LR} ; Calling SP, LR
|
||||
STR LR, [R8, #0] ; Save calling PC
|
||||
MRS R6, SPSR
|
||||
STR R6, [R8, #4] ; Save CPSR
|
||||
STR R0, [R8, #8] ; Save SPSR
|
||||
MOV R0, SP
|
||||
BL rt_hw_trap_dabt
|
||||
ENDP
|
||||
|
||||
Resv_Handler PROC
|
||||
BL rt_hw_trap_resv
|
||||
ENDP
|
||||
|
||||
FIQ_Handler PROC
|
||||
STMFD SP!, {R0-R7,LR}
|
||||
BL rt_hw_trap_fiq
|
||||
LDMFD SP!, {R0-R7,LR}
|
||||
SUBS PC, LR, #4
|
||||
ENDP
|
||||
|
||||
IRQ_Handler PROC
|
||||
STMFD SP!, {R0-R12,LR}
|
||||
BL rt_interrupt_enter
|
||||
BL rt_hw_trap_irq
|
||||
BL rt_interrupt_leave
|
||||
|
||||
; If rt_thread_switch_interrupt_flag set,
|
||||
; jump to rt_hw_context_switch_interrupt_do and don't return
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CMP R1, #1
|
||||
BEQ rt_hw_context_switch_interrupt_do
|
||||
|
||||
LDMFD SP!, {R0-R12,LR}
|
||||
SUBS PC, LR, #4
|
||||
ENDP
|
||||
|
||||
;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) -----------------
|
||||
rt_hw_context_switch_interrupt_do PROC
|
||||
MOV R1, #0 ; Clear flag
|
||||
STR R1, [R0] ; Save to flag variable
|
||||
|
||||
LDMFD SP!, {R0-R12,LR} ; Reload saved registers
|
||||
STMFD SP, {R0-R2} ; Save R0-R2
|
||||
SUB R1, SP, #4*3 ; Save old task's SP to R1
|
||||
SUB R2, LR, #4 ; Save old task's PC to R2
|
||||
|
||||
MRS R0, SPSR ; Get CPSR of interrupt thread
|
||||
|
||||
MSR CPSR_c, #MODE_SVC:OR:NOINT ; Switch to SVC mode and no interrupt
|
||||
|
||||
STMFD SP!, {R2} ; Push old task's PC
|
||||
STMFD SP!, {R3-R12,LR} ; Push old task's LR,R12-R3
|
||||
LDMFD R1, {R1-R3}
|
||||
STMFD SP!, {R1-R3} ; Push old task's R2-R0
|
||||
STMFD SP!, {R0} ; Push old task's CPSR
|
||||
|
||||
LDR R4, =rt_interrupt_from_thread
|
||||
LDR R5, [R4] ; R5 = stack ptr in old tasks's TCB
|
||||
STR SP, [R5] ; Store SP in preempted tasks's TCB
|
||||
|
||||
LDR R6, =rt_interrupt_to_thread
|
||||
LDR R6, [R6] ; R6 = stack ptr in new tasks's TCB
|
||||
LDR SP, [R6] ; Get new task's stack pointer
|
||||
|
||||
LDMFD SP!, {R4} ; Pop new task's SPSR
|
||||
MSR SPSR_cxsf, R4
|
||||
|
||||
LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's R0-R12,LR & PC SPSR to CPSR
|
||||
ENDP
|
||||
|
||||
;*******************************************************************************
|
||||
; User Stack and Heap initialization
|
||||
;*******************************************************************************
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __initial_sp
|
||||
EXPORT __heap_base
|
||||
EXPORT __heap_limit
|
||||
|
||||
ELSE
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
EXPORT __user_initial_stackheap
|
||||
|
||||
__user_initial_stackheap
|
||||
|
||||
LDR R0, = Heap_Mem ; heap base
|
||||
LDR R1, = SVC_STACK_START ; stack base (top-address)
|
||||
LDR R2, = (Heap_Mem + Heap_Size) ; heap limit
|
||||
LDR R3, = (SVC_STACK_START - SVC_STK_SIZE) ; stack limit (low-address)
|
||||
BX LR
|
||||
|
||||
ALIGN
|
||||
|
||||
ENDIF
|
||||
|
||||
END
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety modified from mini2440
|
||||
* 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#define INT_IRQ 0x00
|
||||
#define INT_FIQ 0x01
|
||||
|
||||
extern struct rt_thread *rt_current_thread;
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
|
||||
struct rt_hw_register
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t fp;
|
||||
rt_uint32_t ip;
|
||||
rt_uint32_t sp;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t cpsr;
|
||||
rt_uint32_t ORIG_r0;
|
||||
};
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
/**
|
||||
* this function will show registers of CPU
|
||||
*
|
||||
* @param regs the registers point
|
||||
*/
|
||||
|
||||
void rt_hw_show_register(struct rt_hw_register *regs)
|
||||
{
|
||||
rt_kprintf("Execption:\n");
|
||||
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n",
|
||||
regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n",
|
||||
regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n",
|
||||
regs->r8, regs->r9, regs->r10);
|
||||
rt_kprintf("fp :0x%08x ip :0x%08x\n",
|
||||
regs->fp, regs->ip);
|
||||
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n",
|
||||
regs->sp, regs->lr, regs->pc);
|
||||
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
|
||||
}
|
||||
|
||||
/**
|
||||
* When ARM7TDMI comes across an instruction which it cannot handle,
|
||||
* it takes the undefined instruction trap.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_udef(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("undefined instruction\n");
|
||||
rt_kprintf("thread - %s stack:\n", rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* The software interrupt instruction (SWI) is used for entering
|
||||
* Supervisor mode, usually to request a particular supervisor
|
||||
* function.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_swi(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("software interrupt\n");
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during an instruction prefetch.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_pabt(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("prefetch abort\n");
|
||||
rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during a data access.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_dabt(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_hw_show_register(regs);
|
||||
|
||||
rt_kprintf("data abort\n");
|
||||
rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally, system will never reach here
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_resv(struct rt_hw_register *regs)
|
||||
{
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(regs);
|
||||
if (result == RT_EOK) return;
|
||||
}
|
||||
rt_kprintf("not used\n");
|
||||
rt_hw_show_register(regs);
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
|
||||
extern void rt_interrupt_dispatch(rt_uint32_t fiq_irq);
|
||||
|
||||
void rt_hw_trap_irq(void)
|
||||
{
|
||||
rt_interrupt_dispatch(INT_IRQ);
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq(void)
|
||||
{
|
||||
rt_interrupt_dispatch(INT_FIQ);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-11-07 weety first version
|
||||
*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#include "armv6.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
.macro PRINT, str
|
||||
#ifdef DEBUG
|
||||
stmfd sp!, {r0-r3, ip, lr}
|
||||
add r0, pc, #4
|
||||
bl rt_kprintf
|
||||
b 1f
|
||||
.asciz "UNDEF: \str\n"
|
||||
.balign 4
|
||||
1: ldmfd sp!, {r0-r3, ip, lr}
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro PRINT1, str, arg
|
||||
#ifdef DEBUG
|
||||
stmfd sp!, {r0-r3, ip, lr}
|
||||
mov r1, \arg
|
||||
add r0, pc, #4
|
||||
bl rt_kprintf
|
||||
b 1f
|
||||
.asciz "UNDEF: \str\n"
|
||||
.balign 4
|
||||
1: ldmfd sp!, {r0-r3, ip, lr}
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro PRINT3, str, arg1, arg2, arg3
|
||||
#ifdef DEBUG
|
||||
stmfd sp!, {r0-r3, ip, lr}
|
||||
mov r3, \arg3
|
||||
mov r2, \arg2
|
||||
mov r1, \arg1
|
||||
add r0, pc, #4
|
||||
bl rt_kprintf
|
||||
b 1f
|
||||
.asciz "UNDEF: \str\n"
|
||||
.balign 4
|
||||
1: ldmfd sp!, {r0-r3, ip, lr}
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro get_current_thread, rd
|
||||
ldr \rd, .current_thread
|
||||
ldr \rd, [\rd]
|
||||
.endm
|
||||
|
||||
.current_thread:
|
||||
.word rt_current_thread
|
||||
|
||||
#ifdef RT_USING_NEON
|
||||
.align 6
|
||||
|
||||
/* is the neon instuction on arm mode? */
|
||||
.neon_opcode:
|
||||
.word 0xfe000000 @ mask
|
||||
.word 0xf2000000 @ opcode
|
||||
|
||||
.word 0xff100000 @ mask
|
||||
.word 0xf4000000 @ opcode
|
||||
|
||||
.word 0x00000000 @ end mask
|
||||
.word 0x00000000 @ end opcode
|
||||
#endif
|
||||
|
||||
/* undefined instruction exception processing */
|
||||
.globl undef_entry
|
||||
undef_entry:
|
||||
PRINT1 "r0=0x%08x", r0
|
||||
PRINT1 "r2=0x%08x", r2
|
||||
PRINT1 "r9=0x%08x", r9
|
||||
PRINT1 "sp=0x%08x", sp
|
||||
|
||||
#ifdef RT_USING_NEON
|
||||
ldr r6, .neon_opcode
|
||||
__check_neon_instruction:
|
||||
ldr r7, [r6], #4 @ load mask value
|
||||
cmp r7, #0 @ end mask?
|
||||
beq __check_vfp_instruction
|
||||
and r8, r0, r7
|
||||
ldr r7, [r6], #4 @ load opcode value
|
||||
cmp r8, r7 @ is NEON instruction?
|
||||
bne __check_neon_instruction
|
||||
b vfp_entry
|
||||
__check_vfp_instruction:
|
||||
#endif
|
||||
tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC instruction has bit 27
|
||||
tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 instruction
|
||||
moveq pc, lr @ no vfp coprocessor instruction, return
|
||||
get_current_thread r10
|
||||
and r8, r0, #0x00000f00 @ get coprocessor number
|
||||
PRINT1 "CP=0x%08x", r8
|
||||
add pc, pc, r8, lsr #6
|
||||
nop
|
||||
mov pc, lr @ CP0
|
||||
mov pc, lr @ CP1
|
||||
mov pc, lr @ CP2
|
||||
mov pc, lr @ CP3
|
||||
mov pc, lr @ CP4
|
||||
mov pc, lr @ CP5
|
||||
mov pc, lr @ CP6
|
||||
mov pc, lr @ CP7
|
||||
mov pc, lr @ CP8
|
||||
mov pc, lr @ CP9
|
||||
mov pc, lr @ CP10 VFP
|
||||
mov pc, lr @ CP11 VFP
|
||||
mov pc, lr @ CP12
|
||||
mov pc, lr @ CP13
|
||||
mov pc, lr @ CP14 DEBUG
|
||||
mov pc, lr @ CP15 SYS CONTROL
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __ARMV6_H__
|
||||
#define __ARMV6_H__
|
||||
|
||||
|
||||
/*****************************/
|
||||
/* CPU Mode */
|
||||
/*****************************/
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct rt_hw_register
|
||||
{
|
||||
rt_uint32_t cpsr;
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t fp;
|
||||
rt_uint32_t ip;
|
||||
rt_uint32_t sp;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
};
|
||||
#if(0)
|
||||
struct rt_hw_register{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t fp;
|
||||
rt_uint32_t ip;
|
||||
rt_uint32_t sp;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t cpsr;
|
||||
rt_uint32_t ORIG_r0;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* rt_hw_register offset */
|
||||
#define S_FRAME_SIZE 68
|
||||
|
||||
#define S_PC 64
|
||||
#define S_LR 60
|
||||
#define S_SP 56
|
||||
#define S_IP 52
|
||||
#define S_FP 48
|
||||
#define S_R10 44
|
||||
#define S_R9 40
|
||||
#define S_R8 36
|
||||
#define S_R7 32
|
||||
#define S_R6 28
|
||||
#define S_R5 24
|
||||
#define S_R4 20
|
||||
#define S_R3 16
|
||||
#define S_R2 12
|
||||
#define S_R1 8
|
||||
#define S_R0 4
|
||||
#define S_CPSR 0
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety copy from mini2440
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \addtogroup ARMv6
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#define NOINT 0xc0
|
||||
#define FPEXC_EN (1 << 30) /* VFP enable bit */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
mrs r0, cpsr
|
||||
cpsid if
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
msr cpsr_c, r0
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* r0 --> from
|
||||
* r1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
|
||||
stmfd sp!, {r0-r12, lr} @ push lr & register file
|
||||
|
||||
mrs r4, cpsr
|
||||
tst lr, #0x01
|
||||
orrne r4, r4, #0x20 @ it's thumb code
|
||||
|
||||
stmfd sp!, {r4} @ push cpsr
|
||||
|
||||
str sp, [r0] @ store sp in preempted tasks TCB
|
||||
ldr sp, [r1] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task cpsr to spsr
|
||||
msr spsr_cxsf, r4
|
||||
_do_switch:
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* r0 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
ldr sp, [r0] @ get new task stack pointer
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task spsr
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
bic r4, r4, #0x20 @ must be ARM mode
|
||||
msr cpsr_cxsf, r4
|
||||
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
str r3, [r2]
|
||||
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
str r0, [r2]
|
||||
_reswitch:
|
||||
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety modified from mini2440
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
|
||||
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
|
||||
|
||||
extern void machine_reset(void);
|
||||
extern void machine_shutdown(void);
|
||||
|
||||
#ifdef __GNUC__
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
__asm__ __volatile__( \
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"orr r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
:"r" (bit) \
|
||||
:"memory");
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
__asm__ __volatile__( \
|
||||
"mrc p15,0,r0,c1,c0,0\n\t" \
|
||||
"bic r0,r0,%0\n\t" \
|
||||
"mcr p15,0,r0,c1,c0,0" \
|
||||
: \
|
||||
:"r" (bit) \
|
||||
:"memory");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __CC_ARM
|
||||
rt_inline rt_uint32_t cp15_rd(void)
|
||||
{
|
||||
rt_uint32_t i;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, i, c1, c0, 0
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
rt_inline void cache_enable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline void cache_disable(rt_uint32_t bit)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
__asm
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, bit
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_enable()
|
||||
{
|
||||
cache_enable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable I-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_icache_disable()
|
||||
{
|
||||
cache_disable(ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of I-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_icache_status()
|
||||
{
|
||||
return (cp15_rd() & ICACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* enable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_enable()
|
||||
{
|
||||
cache_enable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* disable D-Cache
|
||||
*
|
||||
*/
|
||||
void rt_hw_cpu_dcache_disable()
|
||||
{
|
||||
cache_disable(DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the status of D-Cache
|
||||
*
|
||||
*/
|
||||
rt_base_t rt_hw_cpu_dcache_status()
|
||||
{
|
||||
return (cp15_rd() & DCACHE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset cpu by dog's time-out
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset()
|
||||
{
|
||||
|
||||
rt_kprintf("Restarting system...\n");
|
||||
machine_reset();
|
||||
|
||||
while(1); /* loop forever and wait for reset to happen */
|
||||
|
||||
/* NEVER REACHED */
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
machine_shutdown();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
register rt_uint32_t x;
|
||||
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
__asm
|
||||
{
|
||||
rsb x, value, #0
|
||||
and x, x, value
|
||||
clz x, x
|
||||
rsb x, x, #32
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
__ASM("RSB r4, r0, #0");
|
||||
__ASM("AND r4, r4, r0");
|
||||
__ASM("CLZ r4, r4");
|
||||
__ASM("RSB r0, r4, #32");
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
return value;
|
||||
|
||||
value &= (-value);
|
||||
asm ("clz %0, %1": "=r"(value) :"r"(value));
|
||||
|
||||
return (32 - value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "mmu.h"
|
||||
|
||||
#ifdef __CC_ARM
|
||||
void mmu_setttbase(rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c8, c7, 0
|
||||
}
|
||||
|
||||
value = 0x55555555;
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c3, c0, 0
|
||||
mcr p15, 0, i, c2, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_set_domain(rt_uint32_t i)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15,0, i, c3, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x01
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x1000
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x04
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
orr value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mrc p15, 0, value, c1, c0, 0
|
||||
bic value, value, #0x02
|
||||
mcr p15, 0, value, c1, c0, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, index, c7, c14, 2
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while(ptr < buffer + size)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
MCR p15, 0, ptr, c7, c14, 1
|
||||
}
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
MCR p15, 0, ptr, c7, c10, 1
|
||||
}
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
__asm volatile
|
||||
{
|
||||
MCR p15, 0, ptr, c7, c6, 1
|
||||
}
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c8, c7, 0
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c7, c5, 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
value = 0;
|
||||
|
||||
__asm volatile
|
||||
{
|
||||
mcr p15, 0, value, c7, c6, 0
|
||||
}
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
void mmu_setttbase(register rt_uint32_t i)
|
||||
{
|
||||
register rt_uint32_t value;
|
||||
|
||||
/* Invalidates all TLBs.Domain access is selected as
|
||||
* client by configuring domain access register,
|
||||
* in that case access controlled by permission value
|
||||
* set by page table entry
|
||||
*/
|
||||
value = 0;
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
|
||||
|
||||
value = 0x55555555;
|
||||
asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
|
||||
asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
|
||||
}
|
||||
|
||||
void mmu_set_domain(register rt_uint32_t i)
|
||||
{
|
||||
asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= 0x1;
|
||||
/* Enables the extended page tables to be configured for
|
||||
the hardware page translation mechanism, Subpage AP bits disabled */
|
||||
i |= (1 << 23); /* support for ARMv6 MMU features */
|
||||
i |= (1 << 13); /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~0x1;
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable_icache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= (1 << 12);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable_dcache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= (1 << 2);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable_icache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~(1 << 12);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable_dcache()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~(1 << 2);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_enable_alignfault()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i |= (1 << 1);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_disable_alignfault()
|
||||
{
|
||||
register rt_uint32_t i;
|
||||
|
||||
/* read control register */
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
|
||||
|
||||
i &= ~(1 << 1);
|
||||
|
||||
/* write back to control register */
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_cache_index(int index)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index));
|
||||
}
|
||||
|
||||
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while(ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr));
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr));
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
|
||||
{
|
||||
unsigned int ptr;
|
||||
|
||||
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
while (ptr < buffer + size)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr));
|
||||
ptr += CACHE_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_invalidate_tlb()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0));
|
||||
}
|
||||
|
||||
void mmu_invalidate_icache()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
|
||||
}
|
||||
|
||||
void mmu_invalidate_dcache_all()
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 0": :"r" (0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* level1 page table */
|
||||
static volatile unsigned int _pgd_table[4*1024] ALIGN(16*1024);
|
||||
/*
|
||||
* level2 page table
|
||||
* RT_MMU_PTE_SIZE must be 1024*n
|
||||
*/
|
||||
#define RT_MMU_PTE_SIZE 4096
|
||||
static volatile unsigned int _pte_table[RT_MMU_PTE_SIZE] ALIGN(1*1024);
|
||||
|
||||
void mmu_create_pgd(struct mem_desc *mdesc)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile int i, nSec;
|
||||
pTT = (rt_uint32_t *)_pgd_table + (mdesc->vaddr_start >> 20);
|
||||
nSec = (mdesc->vaddr_end >> 20) - (mdesc->vaddr_start >> 20);
|
||||
for(i = 0; i <= nSec; i++)
|
||||
{
|
||||
*pTT = mdesc->sect_attr | (((mdesc->paddr_start >> 20) + i) << 20);
|
||||
pTT++;
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_create_pte(struct mem_desc *mdesc)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile rt_uint32_t *p_pteentry;
|
||||
int i;
|
||||
rt_uint32_t vaddr;
|
||||
rt_uint32_t total_page = 0;
|
||||
rt_uint32_t pte_offset = 0;
|
||||
rt_uint32_t sect_attr = 0;
|
||||
|
||||
total_page = (mdesc->vaddr_end >> 12) - (mdesc->vaddr_start >> 12) + 1;
|
||||
pte_offset = mdesc->sect_attr & 0xfffffc00;
|
||||
sect_attr = mdesc->sect_attr & 0x3ff;
|
||||
vaddr = mdesc->vaddr_start;
|
||||
|
||||
for(i = 0; i < total_page; i++)
|
||||
{
|
||||
pTT = (rt_uint32_t *)_pgd_table + (vaddr >> 20);
|
||||
if (*pTT == 0) /* Level 1 page table item not used, now update pgd item */
|
||||
{
|
||||
*pTT = pte_offset | sect_attr;
|
||||
p_pteentry = (rt_uint32_t *)pte_offset +
|
||||
((vaddr & 0x000ff000) >> 12);
|
||||
pte_offset += 1024;
|
||||
}
|
||||
else /* using old Level 1 page table item */
|
||||
{
|
||||
p_pteentry = (rt_uint32_t *)(*pTT & 0xfffffc00) +
|
||||
((vaddr & 0x000ff000) >> 12);
|
||||
}
|
||||
|
||||
|
||||
*p_pteentry = mdesc->page_attr | (((mdesc->paddr_start >> 12) + i) << 12);
|
||||
vaddr += 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
static void build_pte_mem_desc(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
rt_uint32_t pte_offset = 0;
|
||||
rt_uint32_t nsec = 0;
|
||||
/* set page table */
|
||||
for (; size > 0; size--)
|
||||
{
|
||||
if (mdesc->mapped_mode == PAGE_MAPPED)
|
||||
{
|
||||
nsec = (RT_ALIGN(mdesc->vaddr_end, 0x100000) - RT_ALIGN_DOWN(mdesc->vaddr_start, 0x100000)) >> 20;
|
||||
mdesc->sect_attr |= (((rt_uint32_t)_pte_table)& 0xfffffc00) + pte_offset;
|
||||
pte_offset += nsec << 10;
|
||||
}
|
||||
if (pte_offset >= RT_MMU_PTE_SIZE)
|
||||
{
|
||||
rt_kprintf("PTE table size too little\n");
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
mdesc++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
/* disable I/D cache */
|
||||
mmu_disable_dcache();
|
||||
mmu_disable_icache();
|
||||
mmu_disable();
|
||||
mmu_invalidate_tlb();
|
||||
|
||||
/* clear pgd and pte table */
|
||||
rt_memset((void *)_pgd_table, 0, 16*1024);
|
||||
rt_memset((void *)_pte_table, 0, RT_MMU_PTE_SIZE);
|
||||
build_pte_mem_desc(mdesc, size);
|
||||
/* set page table */
|
||||
for (; size > 0; size--)
|
||||
{
|
||||
if (mdesc->mapped_mode == SECT_MAPPED)
|
||||
{
|
||||
mmu_create_pgd(mdesc);
|
||||
}
|
||||
else
|
||||
{
|
||||
mmu_create_pte(mdesc);
|
||||
}
|
||||
|
||||
mdesc++;
|
||||
}
|
||||
|
||||
/* set MMU table address */
|
||||
mmu_setttbase((rt_uint32_t)_pgd_table);
|
||||
|
||||
/* enables MMU */
|
||||
mmu_enable();
|
||||
|
||||
/* enable Instruction Cache */
|
||||
mmu_enable_icache();
|
||||
|
||||
/* enable Data Cache */
|
||||
mmu_enable_dcache();
|
||||
|
||||
mmu_invalidate_icache();
|
||||
mmu_invalidate_dcache_all();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __MMU_H__
|
||||
#define __MMU_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define CACHE_LINE_SIZE 32
|
||||
|
||||
/*
|
||||
* Hardware page table definitions.
|
||||
*
|
||||
* + Level 1 descriptor (PGD)
|
||||
* - common
|
||||
*/
|
||||
#define PGD_TYPE_MASK (3 << 0)
|
||||
#define PGD_TYPE_FAULT (0 << 0)
|
||||
#define PGD_TYPE_TABLE (1 << 0)
|
||||
#define PGD_TYPE_SECT (2 << 0)
|
||||
#define PGD_BIT4 (1 << 4)
|
||||
#define PGD_DOMAIN(x) ((x) << 5)
|
||||
#define PGD_PROTECTION (1 << 9) /* ARMv5 */
|
||||
/*
|
||||
* - section
|
||||
*/
|
||||
#define PGD_SECT_BUFFERABLE (1 << 2)
|
||||
#define PGD_SECT_CACHEABLE (1 << 3)
|
||||
#define PGD_SECT_XN (1 << 4) /* ARMv6 */
|
||||
#define PGD_SECT_AP0 (1 << 10)
|
||||
#define PGD_SECT_AP1 (1 << 11)
|
||||
#define PGD_SECT_TEX(x) ((x) << 12) /* ARMv5 */
|
||||
#define PGD_SECT_APX (1 << 15) /* ARMv6 */
|
||||
#define PGD_SECT_S (1 << 16) /* ARMv6 */
|
||||
#define PGD_SECT_nG (1 << 17) /* ARMv6 */
|
||||
#define PGD_SECT_SUPER (1 << 18) /* ARMv6 */
|
||||
|
||||
#define PGD_SECT_UNCACHED (0)
|
||||
#define PGD_SECT_BUFFERED (PGD_SECT_BUFFERABLE)
|
||||
#define PGD_SECT_WT (PGD_SECT_CACHEABLE)
|
||||
#define PGD_SECT_WB (PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
|
||||
#define PGD_SECT_MINICACHE (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE)
|
||||
#define PGD_SECT_WBWA (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
|
||||
#define PGD_SECT_NONSHARED_DEV (PGD_SECT_TEX(2))
|
||||
|
||||
|
||||
/*
|
||||
* + Level 2 descriptor (PTE)
|
||||
* - common
|
||||
*/
|
||||
#define PTE_TYPE_MASK (3 << 0)
|
||||
#define PTE_TYPE_FAULT (0 << 0)
|
||||
#define PTE_TYPE_LARGE (1 << 0)
|
||||
#define PTE_TYPE_SMALL (2 << 0)
|
||||
#define PTE_TYPE_EXT (3 << 0) /* ARMv5 */
|
||||
#define PTE_BUFFERABLE (1 << 2)
|
||||
#define PTE_CACHEABLE (1 << 3)
|
||||
|
||||
/*
|
||||
* - extended small page/tiny page
|
||||
*/
|
||||
#define PTE_EXT_XN (1 << 0) /* ARMv6 */
|
||||
#define PTE_EXT_AP_MASK (3 << 4)
|
||||
#define PTE_EXT_AP0 (1 << 4)
|
||||
#define PTE_EXT_AP1 (2 << 4)
|
||||
#define PTE_EXT_AP_UNO_SRO (0 << 4)
|
||||
#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0)
|
||||
#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1)
|
||||
#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
|
||||
#define PTE_EXT_TEX(x) ((x) << 6) /* ARMv5 */
|
||||
#define PTE_EXT_APX (1 << 9) /* ARMv6 */
|
||||
#define PTE_EXT_SHARED (1 << 10) /* ARMv6 */
|
||||
#define PTE_EXT_NG (1 << 11) /* ARMv6 */
|
||||
|
||||
/*
|
||||
* - small page
|
||||
*/
|
||||
#define PTE_SMALL_AP_MASK (0xff << 4)
|
||||
#define PTE_SMALL_AP_UNO_SRO (0x00 << 4)
|
||||
#define PTE_SMALL_AP_UNO_SRW (0x55 << 4)
|
||||
#define PTE_SMALL_AP_URO_SRW (0xaa << 4)
|
||||
#define PTE_SMALL_AP_URW_SRW (0xff << 4)
|
||||
|
||||
|
||||
/*
|
||||
* sector table properities
|
||||
*/
|
||||
#define SECT_CB (PGD_SECT_CACHEABLE|PGD_SECT_BUFFERABLE) //cache_on, write_back
|
||||
#define SECT_CNB (PGD_SECT_CACHEABLE) //cache_on, write_through
|
||||
#define SECT_NCB (PGD_SECT_BUFFERABLE) //cache_off,WR_BUF on
|
||||
#define SECT_NCNB (0 << 2) //cache_off,WR_BUF off
|
||||
|
||||
#define SECT_AP_RW (PGD_SECT_AP0|PGD_SECT_AP1) //supervisor=RW, user=RW
|
||||
#define SECT_AP_RO (PGD_SECT_AP0|PGD_SECT_AP1|PGD_SECT_APX) //supervisor=RO, user=RO
|
||||
|
||||
#define SECT_RWX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read/Write/executable, cache, write back */
|
||||
#define SECT_RWX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read/Write/executable, cache, write through */
|
||||
#define SECT_RWX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read/Write/executable without cache and write buffer */
|
||||
#define SECT_RWX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read/Write without cache and write buffer */
|
||||
|
||||
#define SECT_RWNX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write back */
|
||||
#define SECT_RWNX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write through */
|
||||
#define SECT_RWNX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
|
||||
#define SECT_RWNX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
|
||||
|
||||
|
||||
#define SECT_ROX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read Only/executable, cache, write back */
|
||||
#define SECT_ROX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read Only/executable, cache, write through */
|
||||
#define SECT_ROX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read Only/executable without cache and write buffer */
|
||||
#define SECT_ROX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read Only without cache and write buffer */
|
||||
|
||||
#define SECT_RONX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write back */
|
||||
#define SECT_RONX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write through */
|
||||
#define SECT_RONX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
|
||||
#define SECT_RONX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
|
||||
|
||||
#define SECT_TO_PAGE (PGD_DOMAIN(0)|PGD_TYPE_TABLE) /* Level 2 descriptor (PTE) entry properity */
|
||||
|
||||
/*
|
||||
* page table properities
|
||||
*/
|
||||
#define PAGE_CB (PTE_BUFFERABLE|PTE_CACHEABLE) //cache_on, write_back
|
||||
#define PAGE_CNB (PTE_CACHEABLE) //cache_on, write_through
|
||||
#define PAGE_NCB (PTE_BUFFERABLE) //cache_off,WR_BUF on
|
||||
#define PAGE_NCNB (0 << 2) //cache_off,WR_BUF off
|
||||
|
||||
#define PAGE_AP_RW (PTE_EXT_AP0|PTE_EXT_AP1) //supervisor=RW, user=RW
|
||||
#define PAGE_AP_RO (PTE_EXT_AP0|PTE_EXT_AP1|PTE_EXT_APX) //supervisor=RO, user=RO
|
||||
|
||||
#define PAGE_RWX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write back */
|
||||
#define PAGE_RWX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write through */
|
||||
#define PAGE_RWX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write/executable without cache and write buffer */
|
||||
#define PAGE_RWX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write without cache and write buffer */
|
||||
|
||||
#define PAGE_RWNX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write back */
|
||||
#define PAGE_RWNX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write through */
|
||||
#define PAGE_RWNX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
|
||||
#define PAGE_RWNX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
|
||||
|
||||
|
||||
#define PAGE_ROX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write back */
|
||||
#define PAGE_ROX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write through */
|
||||
#define PAGE_ROX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only/executable without cache and write buffer */
|
||||
#define PAGE_ROX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only without cache and write buffer */
|
||||
|
||||
#define PAGE_RONX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write back */
|
||||
#define PAGE_RONX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write through */
|
||||
#define PAGE_RONX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
|
||||
#define PAGE_RONX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
|
||||
|
||||
|
||||
#define DESC_SEC (0x2|(1<<4))
|
||||
#define CB (3<<2) //cache_on, write_back
|
||||
#define CNB (2<<2) //cache_on, write_through
|
||||
#define NCB (1<<2) //cache_off,WR_BUF on
|
||||
#define NCNB (0<<2) //cache_off,WR_BUF off
|
||||
#define AP_RW (3<<10) //supervisor=RW, user=RW
|
||||
#define AP_RO (2<<10) //supervisor=RW, user=RO
|
||||
|
||||
#define DOMAIN_FAULT (0x0)
|
||||
#define DOMAIN_CHK (0x1)
|
||||
#define DOMAIN_NOTCHK (0x3)
|
||||
#define DOMAIN0 (0x0<<5)
|
||||
#define DOMAIN1 (0x1<<5)
|
||||
|
||||
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
|
||||
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
|
||||
|
||||
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
|
||||
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
|
||||
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
|
||||
|
||||
struct mem_desc {
|
||||
rt_uint32_t vaddr_start;
|
||||
rt_uint32_t vaddr_end;
|
||||
rt_uint32_t paddr_start;
|
||||
rt_uint32_t sect_attr; /* when page mapped */
|
||||
rt_uint32_t page_attr; /* only sector mapped valid */
|
||||
rt_uint32_t mapped_mode;
|
||||
#define SECT_MAPPED 0
|
||||
#define PAGE_MAPPED 1
|
||||
};
|
||||
|
||||
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-01-13 weety copy from mini2440
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
/*****************************/
|
||||
/* CPU Mode */
|
||||
/*****************************/
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define ABORTMODE 0x17
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-11-07 weety first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include "vfp.h"
|
||||
|
||||
#ifdef RT_USING_VFP
|
||||
|
||||
void vfp_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int value;
|
||||
asm volatile ("mrc p15, 0, %0, c1, c0, 2"
|
||||
:"=r"(value)
|
||||
:);
|
||||
value |= 0xf00000;/*enable CP10, CP11 user access*/
|
||||
asm volatile("mcr p15, 0, %0, c1, c0, 2"
|
||||
:
|
||||
:"r"(value));
|
||||
|
||||
asm volatile("fmrx %0, fpexc"
|
||||
:"=r"(value));
|
||||
value |=(1<<30);
|
||||
asm volatile("fmxr fpexc, %0"
|
||||
:
|
||||
:"r"(value));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2014-11-07 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __VFP_H__
|
||||
#define __VFP_H__
|
||||
|
||||
/* FPSID register bits */
|
||||
#define FPSID_IMPLEMENTER_BIT (24)
|
||||
#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT)
|
||||
#define FPSID_SW (1 << 23)
|
||||
#define FPSID_FORMAT_BIT (21)
|
||||
#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT)
|
||||
#define FPSID_NODOUBLE (1 << 20)
|
||||
#define FPSID_ARCH_BIT (16)
|
||||
#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT)
|
||||
#define FPSID_PART_BIT (8)
|
||||
#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT)
|
||||
#define FPSID_VARIANT_BIT (4)
|
||||
#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT)
|
||||
#define FPSID_REVISION_BIT (0)
|
||||
#define FPSID_REVISION_MASK (0xF << FPSID_REVISION_BIT)
|
||||
|
||||
/* FPSCR register bits */
|
||||
#define FPSCR_DN (1<<25) /* Default NaN mode enable bit */
|
||||
#define FPSCR_FZ (1<<24) /* Flush-to-zero mode enable bit */
|
||||
#define FPSCR_RN (0<<22) /* Round to nearest (RN) mode */
|
||||
#define FPSCR_RP (1<<22) /* Round towards plus infinity (RP) mode */
|
||||
#define FPSCR_RM (2<<22) /* Round towards minus infinity (RM) mode */
|
||||
#define FPSCR_RZ (3<<22) /* Round towards zero (RZ) mode */
|
||||
#define FPSCR_RMODE_BIT (22)
|
||||
#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT)
|
||||
#define FPSCR_STRIDE_BIT (20)
|
||||
#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT)
|
||||
#define FPSCR_LENGTH_BIT (16)
|
||||
#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT)
|
||||
#define FPSCR_IDE (1<<15) /* Input Subnormal exception trap enable bit */
|
||||
#define FPSCR_IXE (1<<12) /* Inexact exception trap enable bit */
|
||||
#define FPSCR_UFE (1<<11) /* Underflow exception trap enable bit */
|
||||
#define FPSCR_OFE (1<<10) /* Overflow exception trap enable bit */
|
||||
#define FPSCR_DZE (1<<9) /* Division by Zero exception trap enable bit */
|
||||
#define FPSCR_IOE (1<<8) /* Invalid Operation exception trap enable bit */
|
||||
#define FPSCR_IDC (1<<7) /* Input Subnormal cumulative exception flag */
|
||||
#define FPSCR_IXC (1<<4) /* Inexact cumulative exception flag */
|
||||
#define FPSCR_UFC (1<<3) /* Underflow cumulative exception flag */
|
||||
#define FPSCR_OFC (1<<2) /* Overflow cumulative exception flag */
|
||||
#define FPSCR_DZC (1<<1) /* Division by Zero cumulative exception flag */
|
||||
#define FPSCR_IOC (1<<0) /* Invalid Operation cumulative exception flag */
|
||||
|
||||
/* FPEXC register bits */
|
||||
#define FPEXC_EX (1 << 31) /* When EX is set, the VFP coprocessor is in the exceptional state */
|
||||
#define FPEXC_EN (1 << 30) /* VFP enable bit */
|
||||
#define FPEXC_DEX (1 << 29) /* Defined synchronous instruction exceptional flag */
|
||||
#define FPEXC_FP2V (1 << 28) /* FPINST2 instruction valid flag */
|
||||
#define FPEXC_LENGTH_BIT (8)
|
||||
#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT)
|
||||
#define FPEXC_INV (1 << 7) /* Input exception flag */
|
||||
#define FPEXC_UFC (1 << 3) /* Potential underflow flag */
|
||||
#define FPEXC_OFC (1 << 2) /* Potential overflow flag */
|
||||
#define FPEXC_IOC (1 << 0) /* Potential invalid operation flag */
|
||||
#define FPEXC_TRAP_MASK (FPEXC_INV|FPEXC_UFC|FPEXC_OFC|FPEXC_IOC)
|
||||
|
||||
|
||||
/* MVFR0 register bits */
|
||||
#define MVFR0_A_SIMD_BIT (0)
|
||||
#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT)
|
||||
|
||||
|
||||
/* thread switch micro */
|
||||
#define THREAD_INIT 0
|
||||
#define THREAD_EXIT 1
|
||||
|
||||
/*
|
||||
* get VFP register
|
||||
*/
|
||||
|
||||
#define vmrs(vfp) ({ \
|
||||
rt_uint32_t var; \
|
||||
asm("vmrs %0, "#vfp"" : "=r" (var) : : "cc"); \
|
||||
var; \
|
||||
})
|
||||
|
||||
#define vmsr(vfp, var) \
|
||||
asm("vmsr "#vfp", %0" \
|
||||
: : "r" (var) : "cc")
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-07-29 Bernard first version from QiuYi implementation
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
/*
|
||||
-->High Address,Stack Top
|
||||
PC<------|
|
||||
LR |
|
||||
IP |
|
||||
FP |
|
||||
...... |
|
||||
PC <-| |
|
||||
LR | |
|
||||
IP | |
|
||||
FP---|-- |
|
||||
...... |
|
||||
PC |
|
||||
LR |
|
||||
IP |
|
||||
FP---
|
||||
-->Low Address,Stack Bottom
|
||||
*/
|
||||
void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry)
|
||||
{
|
||||
rt_uint32_t i, pc, func_entry;
|
||||
|
||||
pc = *fp;
|
||||
rt_kprintf("[0x%x]\n", pc-0xC);
|
||||
|
||||
for(i=0; i<10; i++)
|
||||
{
|
||||
fp = (rt_uint32_t *)*(fp - 3);
|
||||
pc = *fp ;
|
||||
|
||||
func_entry = pc - 0xC;
|
||||
|
||||
if(func_entry <= 0x30000000) break;
|
||||
|
||||
if(func_entry == thread_entry)
|
||||
{
|
||||
rt_kprintf("EntryPoint:0x%x\n", func_entry);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
rt_kprintf("[0x%x]\n", func_entry);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry)
|
||||
{
|
||||
/* old compiler implementation */
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
void __div0 (void)
|
||||
{
|
||||
while (1) ;
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
/* $NetBSD: divsi3.S,v 1.5 2005/02/26 22:58:56 perry Exp $ */
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* stack is aligned as there's a possibility of branching to L_overflow
|
||||
* which makes a C call
|
||||
*/
|
||||
.text
|
||||
.align 0
|
||||
.globl __umodsi3
|
||||
.type __umodsi3 , function
|
||||
__umodsi3:
|
||||
stmfd sp!, {lr}
|
||||
sub sp, sp, #4 /* align stack */
|
||||
bl .L_udivide
|
||||
add sp, sp, #4 /* unalign stack */
|
||||
mov r0, r1
|
||||
ldmfd sp!, {pc}
|
||||
|
||||
.text
|
||||
.align 0
|
||||
.globl __modsi3
|
||||
.type __modsi3 , function
|
||||
__modsi3:
|
||||
stmfd sp!, {lr}
|
||||
sub sp, sp, #4 /* align stack */
|
||||
bl .L_divide
|
||||
add sp, sp, #4 /* unalign stack */
|
||||
mov r0, r1
|
||||
ldmfd sp!, {pc}
|
||||
|
||||
.L_overflow:
|
||||
/* XXX should cause a fatal error */
|
||||
mvn r0, #0
|
||||
mov pc, lr
|
||||
|
||||
.text
|
||||
.align 0
|
||||
.globl __udivsi3
|
||||
.type __udivsi3 , function
|
||||
__udivsi3:
|
||||
.L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */
|
||||
eor r0, r1, r0
|
||||
eor r1, r0, r1
|
||||
eor r0, r1, r0
|
||||
/* r0 = r1 / r0; r1 = r1 % r0 */
|
||||
cmp r0, #1
|
||||
bcc .L_overflow
|
||||
beq .L_divide_l0
|
||||
mov ip, #0
|
||||
movs r1, r1
|
||||
bpl .L_divide_l1
|
||||
orr ip, ip, #0x20000000 /* ip bit 0x20000000 = -ve r1 */
|
||||
movs r1, r1, lsr #1
|
||||
orrcs ip, ip, #0x10000000 /* ip bit 0x10000000 = bit 0 of r1 */
|
||||
b .L_divide_l1
|
||||
|
||||
.L_divide_l0: /* r0 == 1 */
|
||||
mov r0, r1
|
||||
mov r1, #0
|
||||
mov pc, lr
|
||||
|
||||
.text
|
||||
.align 0
|
||||
.globl __divsi3
|
||||
.type __divsi3 , function
|
||||
__divsi3:
|
||||
.L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */
|
||||
eor r0, r1, r0
|
||||
eor r1, r0, r1
|
||||
eor r0, r1, r0
|
||||
/* r0 = r1 / r0; r1 = r1 % r0 */
|
||||
cmp r0, #1
|
||||
bcc .L_overflow
|
||||
beq .L_divide_l0
|
||||
ands ip, r0, #0x80000000
|
||||
rsbmi r0, r0, #0
|
||||
ands r2, r1, #0x80000000
|
||||
eor ip, ip, r2
|
||||
rsbmi r1, r1, #0
|
||||
orr ip, r2, ip, lsr #1 /* ip bit 0x40000000 = -ve division */
|
||||
/* ip bit 0x80000000 = -ve remainder */
|
||||
|
||||
.L_divide_l1:
|
||||
mov r2, #1
|
||||
mov r3, #0
|
||||
|
||||
/*
|
||||
* If the highest bit of the dividend is set, we have to be
|
||||
* careful when shifting the divisor. Test this.
|
||||
*/
|
||||
movs r1,r1
|
||||
bpl .L_old_code
|
||||
|
||||
/*
|
||||
* At this point, the highest bit of r1 is known to be set.
|
||||
* We abuse this below in the tst instructions.
|
||||
*/
|
||||
tst r1, r0 /*, lsl #0 */
|
||||
bmi .L_divide_b1
|
||||
tst r1, r0, lsl #1
|
||||
bmi .L_divide_b2
|
||||
tst r1, r0, lsl #2
|
||||
bmi .L_divide_b3
|
||||
tst r1, r0, lsl #3
|
||||
bmi .L_divide_b4
|
||||
tst r1, r0, lsl #4
|
||||
bmi .L_divide_b5
|
||||
tst r1, r0, lsl #5
|
||||
bmi .L_divide_b6
|
||||
tst r1, r0, lsl #6
|
||||
bmi .L_divide_b7
|
||||
tst r1, r0, lsl #7
|
||||
bmi .L_divide_b8
|
||||
tst r1, r0, lsl #8
|
||||
bmi .L_divide_b9
|
||||
tst r1, r0, lsl #9
|
||||
bmi .L_divide_b10
|
||||
tst r1, r0, lsl #10
|
||||
bmi .L_divide_b11
|
||||
tst r1, r0, lsl #11
|
||||
bmi .L_divide_b12
|
||||
tst r1, r0, lsl #12
|
||||
bmi .L_divide_b13
|
||||
tst r1, r0, lsl #13
|
||||
bmi .L_divide_b14
|
||||
tst r1, r0, lsl #14
|
||||
bmi .L_divide_b15
|
||||
tst r1, r0, lsl #15
|
||||
bmi .L_divide_b16
|
||||
tst r1, r0, lsl #16
|
||||
bmi .L_divide_b17
|
||||
tst r1, r0, lsl #17
|
||||
bmi .L_divide_b18
|
||||
tst r1, r0, lsl #18
|
||||
bmi .L_divide_b19
|
||||
tst r1, r0, lsl #19
|
||||
bmi .L_divide_b20
|
||||
tst r1, r0, lsl #20
|
||||
bmi .L_divide_b21
|
||||
tst r1, r0, lsl #21
|
||||
bmi .L_divide_b22
|
||||
tst r1, r0, lsl #22
|
||||
bmi .L_divide_b23
|
||||
tst r1, r0, lsl #23
|
||||
bmi .L_divide_b24
|
||||
tst r1, r0, lsl #24
|
||||
bmi .L_divide_b25
|
||||
tst r1, r0, lsl #25
|
||||
bmi .L_divide_b26
|
||||
tst r1, r0, lsl #26
|
||||
bmi .L_divide_b27
|
||||
tst r1, r0, lsl #27
|
||||
bmi .L_divide_b28
|
||||
tst r1, r0, lsl #28
|
||||
bmi .L_divide_b29
|
||||
tst r1, r0, lsl #29
|
||||
bmi .L_divide_b30
|
||||
tst r1, r0, lsl #30
|
||||
bmi .L_divide_b31
|
||||
/*
|
||||
* instead of:
|
||||
* tst r1, r0, lsl #31
|
||||
* bmi .L_divide_b32
|
||||
*/
|
||||
b .L_divide_b32
|
||||
|
||||
.L_old_code:
|
||||
cmp r1, r0
|
||||
bcc .L_divide_b0
|
||||
cmp r1, r0, lsl #1
|
||||
bcc .L_divide_b1
|
||||
cmp r1, r0, lsl #2
|
||||
bcc .L_divide_b2
|
||||
cmp r1, r0, lsl #3
|
||||
bcc .L_divide_b3
|
||||
cmp r1, r0, lsl #4
|
||||
bcc .L_divide_b4
|
||||
cmp r1, r0, lsl #5
|
||||
bcc .L_divide_b5
|
||||
cmp r1, r0, lsl #6
|
||||
bcc .L_divide_b6
|
||||
cmp r1, r0, lsl #7
|
||||
bcc .L_divide_b7
|
||||
cmp r1, r0, lsl #8
|
||||
bcc .L_divide_b8
|
||||
cmp r1, r0, lsl #9
|
||||
bcc .L_divide_b9
|
||||
cmp r1, r0, lsl #10
|
||||
bcc .L_divide_b10
|
||||
cmp r1, r0, lsl #11
|
||||
bcc .L_divide_b11
|
||||
cmp r1, r0, lsl #12
|
||||
bcc .L_divide_b12
|
||||
cmp r1, r0, lsl #13
|
||||
bcc .L_divide_b13
|
||||
cmp r1, r0, lsl #14
|
||||
bcc .L_divide_b14
|
||||
cmp r1, r0, lsl #15
|
||||
bcc .L_divide_b15
|
||||
cmp r1, r0, lsl #16
|
||||
bcc .L_divide_b16
|
||||
cmp r1, r0, lsl #17
|
||||
bcc .L_divide_b17
|
||||
cmp r1, r0, lsl #18
|
||||
bcc .L_divide_b18
|
||||
cmp r1, r0, lsl #19
|
||||
bcc .L_divide_b19
|
||||
cmp r1, r0, lsl #20
|
||||
bcc .L_divide_b20
|
||||
cmp r1, r0, lsl #21
|
||||
bcc .L_divide_b21
|
||||
cmp r1, r0, lsl #22
|
||||
bcc .L_divide_b22
|
||||
cmp r1, r0, lsl #23
|
||||
bcc .L_divide_b23
|
||||
cmp r1, r0, lsl #24
|
||||
bcc .L_divide_b24
|
||||
cmp r1, r0, lsl #25
|
||||
bcc .L_divide_b25
|
||||
cmp r1, r0, lsl #26
|
||||
bcc .L_divide_b26
|
||||
cmp r1, r0, lsl #27
|
||||
bcc .L_divide_b27
|
||||
cmp r1, r0, lsl #28
|
||||
bcc .L_divide_b28
|
||||
cmp r1, r0, lsl #29
|
||||
bcc .L_divide_b29
|
||||
cmp r1, r0, lsl #30
|
||||
bcc .L_divide_b30
|
||||
.L_divide_b32:
|
||||
cmp r1, r0, lsl #31
|
||||
subhs r1, r1,r0, lsl #31
|
||||
addhs r3, r3,r2, lsl #31
|
||||
.L_divide_b31:
|
||||
cmp r1, r0, lsl #30
|
||||
subhs r1, r1,r0, lsl #30
|
||||
addhs r3, r3,r2, lsl #30
|
||||
.L_divide_b30:
|
||||
cmp r1, r0, lsl #29
|
||||
subhs r1, r1,r0, lsl #29
|
||||
addhs r3, r3,r2, lsl #29
|
||||
.L_divide_b29:
|
||||
cmp r1, r0, lsl #28
|
||||
subhs r1, r1,r0, lsl #28
|
||||
addhs r3, r3,r2, lsl #28
|
||||
.L_divide_b28:
|
||||
cmp r1, r0, lsl #27
|
||||
subhs r1, r1,r0, lsl #27
|
||||
addhs r3, r3,r2, lsl #27
|
||||
.L_divide_b27:
|
||||
cmp r1, r0, lsl #26
|
||||
subhs r1, r1,r0, lsl #26
|
||||
addhs r3, r3,r2, lsl #26
|
||||
.L_divide_b26:
|
||||
cmp r1, r0, lsl #25
|
||||
subhs r1, r1,r0, lsl #25
|
||||
addhs r3, r3,r2, lsl #25
|
||||
.L_divide_b25:
|
||||
cmp r1, r0, lsl #24
|
||||
subhs r1, r1,r0, lsl #24
|
||||
addhs r3, r3,r2, lsl #24
|
||||
.L_divide_b24:
|
||||
cmp r1, r0, lsl #23
|
||||
subhs r1, r1,r0, lsl #23
|
||||
addhs r3, r3,r2, lsl #23
|
||||
.L_divide_b23:
|
||||
cmp r1, r0, lsl #22
|
||||
subhs r1, r1,r0, lsl #22
|
||||
addhs r3, r3,r2, lsl #22
|
||||
.L_divide_b22:
|
||||
cmp r1, r0, lsl #21
|
||||
subhs r1, r1,r0, lsl #21
|
||||
addhs r3, r3,r2, lsl #21
|
||||
.L_divide_b21:
|
||||
cmp r1, r0, lsl #20
|
||||
subhs r1, r1,r0, lsl #20
|
||||
addhs r3, r3,r2, lsl #20
|
||||
.L_divide_b20:
|
||||
cmp r1, r0, lsl #19
|
||||
subhs r1, r1,r0, lsl #19
|
||||
addhs r3, r3,r2, lsl #19
|
||||
.L_divide_b19:
|
||||
cmp r1, r0, lsl #18
|
||||
subhs r1, r1,r0, lsl #18
|
||||
addhs r3, r3,r2, lsl #18
|
||||
.L_divide_b18:
|
||||
cmp r1, r0, lsl #17
|
||||
subhs r1, r1,r0, lsl #17
|
||||
addhs r3, r3,r2, lsl #17
|
||||
.L_divide_b17:
|
||||
cmp r1, r0, lsl #16
|
||||
subhs r1, r1,r0, lsl #16
|
||||
addhs r3, r3,r2, lsl #16
|
||||
.L_divide_b16:
|
||||
cmp r1, r0, lsl #15
|
||||
subhs r1, r1,r0, lsl #15
|
||||
addhs r3, r3,r2, lsl #15
|
||||
.L_divide_b15:
|
||||
cmp r1, r0, lsl #14
|
||||
subhs r1, r1,r0, lsl #14
|
||||
addhs r3, r3,r2, lsl #14
|
||||
.L_divide_b14:
|
||||
cmp r1, r0, lsl #13
|
||||
subhs r1, r1,r0, lsl #13
|
||||
addhs r3, r3,r2, lsl #13
|
||||
.L_divide_b13:
|
||||
cmp r1, r0, lsl #12
|
||||
subhs r1, r1,r0, lsl #12
|
||||
addhs r3, r3,r2, lsl #12
|
||||
.L_divide_b12:
|
||||
cmp r1, r0, lsl #11
|
||||
subhs r1, r1,r0, lsl #11
|
||||
addhs r3, r3,r2, lsl #11
|
||||
.L_divide_b11:
|
||||
cmp r1, r0, lsl #10
|
||||
subhs r1, r1,r0, lsl #10
|
||||
addhs r3, r3,r2, lsl #10
|
||||
.L_divide_b10:
|
||||
cmp r1, r0, lsl #9
|
||||
subhs r1, r1,r0, lsl #9
|
||||
addhs r3, r3,r2, lsl #9
|
||||
.L_divide_b9:
|
||||
cmp r1, r0, lsl #8
|
||||
subhs r1, r1,r0, lsl #8
|
||||
addhs r3, r3,r2, lsl #8
|
||||
.L_divide_b8:
|
||||
cmp r1, r0, lsl #7
|
||||
subhs r1, r1,r0, lsl #7
|
||||
addhs r3, r3,r2, lsl #7
|
||||
.L_divide_b7:
|
||||
cmp r1, r0, lsl #6
|
||||
subhs r1, r1,r0, lsl #6
|
||||
addhs r3, r3,r2, lsl #6
|
||||
.L_divide_b6:
|
||||
cmp r1, r0, lsl #5
|
||||
subhs r1, r1,r0, lsl #5
|
||||
addhs r3, r3,r2, lsl #5
|
||||
.L_divide_b5:
|
||||
cmp r1, r0, lsl #4
|
||||
subhs r1, r1,r0, lsl #4
|
||||
addhs r3, r3,r2, lsl #4
|
||||
.L_divide_b4:
|
||||
cmp r1, r0, lsl #3
|
||||
subhs r1, r1,r0, lsl #3
|
||||
addhs r3, r3,r2, lsl #3
|
||||
.L_divide_b3:
|
||||
cmp r1, r0, lsl #2
|
||||
subhs r1, r1,r0, lsl #2
|
||||
addhs r3, r3,r2, lsl #2
|
||||
.L_divide_b2:
|
||||
cmp r1, r0, lsl #1
|
||||
subhs r1, r1,r0, lsl #1
|
||||
addhs r3, r3,r2, lsl #1
|
||||
.L_divide_b1:
|
||||
cmp r1, r0
|
||||
subhs r1, r1, r0
|
||||
addhs r3, r3, r2
|
||||
.L_divide_b0:
|
||||
|
||||
tst ip, #0x20000000
|
||||
bne .L_udivide_l1
|
||||
mov r0, r3
|
||||
cmp ip, #0
|
||||
rsbmi r1, r1, #0
|
||||
movs ip, ip, lsl #1
|
||||
bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */
|
||||
rsbmi r0, r0, #0
|
||||
mov pc, lr
|
||||
|
||||
.L_udivide_l1:
|
||||
tst ip, #0x10000000
|
||||
mov r1, r1, lsl #1
|
||||
orrne r1, r1, #1
|
||||
mov r3, r3, lsl #1
|
||||
cmp r1, r0
|
||||
subhs r1, r1, r0
|
||||
addhs r3, r3, r2
|
||||
mov r0, r3
|
||||
mov pc, lr
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2008-07-29 Bernard first version from QiuYi implementation
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
void rt_hw_show_memory(rt_uint32_t addr, rt_uint32_t size)
|
||||
{
|
||||
int i = 0, j =0;
|
||||
|
||||
RT_ASSERT(addr);
|
||||
|
||||
addr = addr & ~0xF;
|
||||
size = 4*((size + 3)/4);
|
||||
|
||||
while(i < size)
|
||||
{
|
||||
rt_kprintf("0x%08x: ", addr );
|
||||
|
||||
for(j=0; j<4; j++)
|
||||
{
|
||||
rt_kprintf("0x%08x ", *(rt_uint32_t *)addr);
|
||||
|
||||
addr += 4;
|
||||
i++;
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split('''
|
||||
cache.c
|
||||
cpu.c
|
||||
mmu.c
|
||||
stack.c
|
||||
''')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend('RT_USING_GIC_V2'):
|
||||
src += ['interrupt.c']
|
||||
src += ['gic.c']
|
||||
src += ['trap.c']
|
||||
|
||||
if GetDepend('RT_USING_GIC_V3'):
|
||||
src += ['interrupt.c']
|
||||
src += ['gicv3.c']
|
||||
src += ['trap.c']
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __ARMV7_H__
|
||||
#define __ARMV7_H__
|
||||
|
||||
/* the exception stack without VFP registers */
|
||||
struct rt_hw_exp_stack
|
||||
{
|
||||
unsigned long r0;
|
||||
unsigned long r1;
|
||||
unsigned long r2;
|
||||
unsigned long r3;
|
||||
unsigned long r4;
|
||||
unsigned long r5;
|
||||
unsigned long r6;
|
||||
unsigned long r7;
|
||||
unsigned long r8;
|
||||
unsigned long r9;
|
||||
unsigned long r10;
|
||||
unsigned long fp;
|
||||
unsigned long ip;
|
||||
unsigned long sp;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
unsigned long cpsr;
|
||||
};
|
||||
|
||||
struct rt_hw_stack
|
||||
{
|
||||
unsigned long cpsr;
|
||||
unsigned long r0;
|
||||
unsigned long r1;
|
||||
unsigned long r2;
|
||||
unsigned long r3;
|
||||
unsigned long r4;
|
||||
unsigned long r5;
|
||||
unsigned long r6;
|
||||
unsigned long r7;
|
||||
unsigned long r8;
|
||||
unsigned long r9;
|
||||
unsigned long r10;
|
||||
unsigned long fp;
|
||||
unsigned long ip;
|
||||
unsigned long lr;
|
||||
unsigned long pc;
|
||||
};
|
||||
|
||||
#define USERMODE 0x10
|
||||
#define FIQMODE 0x11
|
||||
#define IRQMODE 0x12
|
||||
#define SVCMODE 0x13
|
||||
#define MONITORMODE 0x16
|
||||
#define ABORTMODE 0x17
|
||||
#define HYPMODE 0x1b
|
||||
#define UNDEFMODE 0x1b
|
||||
#define MODEMASK 0x1f
|
||||
#define NOINT 0xc0
|
||||
|
||||
#define T_Bit (1<<5)
|
||||
#define F_Bit (1<<6)
|
||||
#define I_Bit (1<<7)
|
||||
#define A_Bit (1<<8)
|
||||
#define E_Bit (1<<9)
|
||||
#define J_Bit (1<<24)
|
||||
|
||||
#define PABT_EXCEPTION 0x1
|
||||
#define DABT_EXCEPTION 0x2
|
||||
#define UND_EXCEPTION 0x3
|
||||
#define SWI_EXCEPTION 0x4
|
||||
#define RESV_EXCEPTION 0xF
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-03-29 quanzhao the first version
|
||||
*/
|
||||
#include <rthw.h>
|
||||
#include <rtdef.h>
|
||||
|
||||
rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
|
||||
{
|
||||
rt_uint32_t ctr;
|
||||
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
|
||||
return 4 << (ctr & 0xF);
|
||||
}
|
||||
|
||||
rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
|
||||
{
|
||||
rt_uint32_t ctr;
|
||||
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
|
||||
return 4 << ((ctr >> 16) & 0xF);
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_invalidate(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_icache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 1" :: "r"(start_addr)); /* icimvau */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb\n\tisb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_invalidate(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_inv_range(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t)addr + size;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
|
||||
if ((start_addr & (line_size - 1)) != 0)
|
||||
{
|
||||
start_addr &= ~(line_size - 1);
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr));
|
||||
start_addr += line_size;
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
if ((end_addr & (line_size - 1)) != 0)
|
||||
{
|
||||
end_addr &= ~(line_size - 1);
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(end_addr));
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_clean(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_clean_inv(void *addr, int size)
|
||||
{
|
||||
rt_uint32_t line_size = rt_cpu_dcache_line_size();
|
||||
rt_uint32_t start_addr = (rt_uint32_t)addr;
|
||||
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
|
||||
|
||||
asm volatile ("dmb":::"memory");
|
||||
start_addr &= ~(line_size-1);
|
||||
end_addr &= ~(line_size-1);
|
||||
while (start_addr < end_addr)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr));
|
||||
start_addr += line_size;
|
||||
}
|
||||
asm volatile ("dsb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
|
||||
{
|
||||
if (ops == RT_HW_CACHE_INVALIDATE)
|
||||
rt_hw_cpu_icache_invalidate(addr, size);
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
|
||||
{
|
||||
if (ops == RT_HW_CACHE_FLUSH)
|
||||
rt_hw_cpu_dcache_clean(addr, size);
|
||||
else if (ops == RT_HW_CACHE_INVALIDATE)
|
||||
rt_hw_cpu_dcache_invalidate(addr, size);
|
||||
}
|
||||
|
||||
rt_base_t rt_hw_cpu_icache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_base_t rt_hw_cpu_dcache_status(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
#include "rtconfig.h"
|
||||
.section .text, "ax"
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#define rt_hw_interrupt_disable rt_hw_local_irq_disable
|
||||
#define rt_hw_interrupt_enable rt_hw_local_irq_enable
|
||||
#endif
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.globl rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
mrs r0, cpsr
|
||||
cpsid i
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.globl rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
msr cpsr, r0
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to, struct rt_thread *to_thread);
|
||||
* r0 --> to (thread stack)
|
||||
* r1 --> to_thread
|
||||
*/
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
ldr sp, [r0] @ get new task stack pointer
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
mov r0, r1
|
||||
bl rt_cpus_lock_status_restore
|
||||
#endif /*RT_USING_SMP*/
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
.section .bss.share.isr
|
||||
_guest_switch_lvl:
|
||||
.word 0
|
||||
|
||||
.globl vmm_virq_update
|
||||
|
||||
.section .text.isr, "ax"
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to, struct rt_thread *to_thread);
|
||||
* r0 --> from (from_thread stack)
|
||||
* r1 --> to (to_thread stack)
|
||||
* r2 --> to_thread
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
|
||||
stmfd sp!, {r0-r12, lr} @ push lr & register file
|
||||
|
||||
mrs r4, cpsr
|
||||
tst lr, #0x01
|
||||
orrne r4, r4, #0x20 @ it's thumb code
|
||||
|
||||
stmfd sp!, {r4} @ push cpsr
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
stmfd sp, {r13, r14}^ @ push usr_sp usr_lr
|
||||
sub sp, #8
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
vmrs r6, fpexc
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
vstmdb sp!, {d0-d15}
|
||||
vstmdb sp!, {d16-d31}
|
||||
vmrs r5, fpscr
|
||||
stmfd sp!, {r5}
|
||||
1:
|
||||
stmfd sp!, {r6}
|
||||
#endif
|
||||
|
||||
str sp, [r0] @ store sp in preempted tasks TCB
|
||||
ldr sp, [r1] @ get new task stack pointer
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
mov r0, r2
|
||||
bl rt_cpus_lock_status_restore
|
||||
#endif /*RT_USING_SMP*/
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
|
||||
*/
|
||||
.equ Mode_USR, 0x10
|
||||
.equ Mode_FIQ, 0x11
|
||||
.equ Mode_IRQ, 0x12
|
||||
.equ Mode_SVC, 0x13
|
||||
.equ Mode_ABT, 0x17
|
||||
.equ Mode_UND, 0x1B
|
||||
.equ Mode_SYS, 0x1F
|
||||
|
||||
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
|
||||
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
|
||||
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
.globl rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch_interrupt:
|
||||
#ifdef RT_USING_SMP
|
||||
/* r0 :svc_mod context
|
||||
* r1 :addr of from_thread's sp
|
||||
* r2 :addr of to_thread's sp
|
||||
* r3 :to_thread's tcb
|
||||
*/
|
||||
|
||||
str r0, [r1]
|
||||
|
||||
ldr sp, [r2]
|
||||
mov r0, r3
|
||||
bl rt_cpus_lock_status_restore
|
||||
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
#else /*RT_USING_SMP*/
|
||||
ldr r2, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [r2]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
ldr ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
str r0, [ip]
|
||||
str r3, [r2]
|
||||
_reswitch:
|
||||
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
.global rt_hw_context_switch_exit
|
||||
rt_hw_context_switch_exit:
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#ifdef RT_USING_SIGNALS
|
||||
mov r0, sp
|
||||
cps #Mode_IRQ
|
||||
bl rt_signal_check
|
||||
cps #Mode_SVC
|
||||
mov sp, r0
|
||||
#endif
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
ldmfd sp!, {r6}
|
||||
vmsr fpexc, r6
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
ldmfd sp!, {r5}
|
||||
vmsr fpscr, r5
|
||||
vldmia sp!, {d16-d31}
|
||||
vldmia sp!, {d0-d15}
|
||||
1:
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
ldmfd sp, {r13, r14}^ /* usr_sp, usr_lr */
|
||||
add sp, #8
|
||||
#endif
|
||||
ldmfd sp!, {r1}
|
||||
msr spsr_cxsf, r1 /* original mode */
|
||||
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-03-25 quanzhao the first version
|
||||
*/
|
||||
#ifndef __CP15_H__
|
||||
#define __CP15_H__
|
||||
|
||||
#define __get_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
||||
#define __set_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
||||
#define __get_cp64(cp, op1, Rt, CRm) __asm__ volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
|
||||
#define __set_cp64(cp, op1, Rt, CRm) __asm__ volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
|
||||
|
||||
int rt_hw_cpu_id(void);
|
||||
void rt_cpu_mmu_disable(void);
|
||||
void rt_cpu_mmu_enable(void);
|
||||
void rt_cpu_tlb_set(volatile unsigned long*);
|
||||
|
||||
void rt_cpu_dcache_clean_flush(void);
|
||||
void rt_cpu_icache_flush(void);
|
||||
|
||||
void rt_cpu_vector_set_base(unsigned int addr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
.weak rt_hw_cpu_id
|
||||
rt_hw_cpu_id:
|
||||
mrc p15, #0, r0, c0, c0, #5 @ read multiprocessor affinity register
|
||||
ldr r1, =0xFFFF03 @ Affinity mask off, leaving CPU ID field, [0:1]CPU ID, [8:15]Cluster ID Aff1, [16:23]Cluster ID Aff2
|
||||
and r0, r0, r1
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_vector_set_base
|
||||
rt_cpu_vector_set_base:
|
||||
/* clear SCTRL.V to customize the vector address */
|
||||
mrc p15, #0, r1, c1, c0, #0
|
||||
bic r1, #(1 << 13)
|
||||
mcr p15, #0, r1, c1, c0, #0
|
||||
/* set up the vector address */
|
||||
mcr p15, #0, r0, c12, c0, #0
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_dcache_enable
|
||||
rt_hw_cpu_dcache_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x00000004
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_icache_enable
|
||||
rt_hw_cpu_icache_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x00001000
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
_FLD_MAX_WAY:
|
||||
.word 0x3ff
|
||||
_FLD_MAX_IDX:
|
||||
.word 0x7fff
|
||||
|
||||
.globl rt_cpu_dcache_clean_flush
|
||||
rt_cpu_dcache_clean_flush:
|
||||
push {r4-r11}
|
||||
dmb
|
||||
mrc p15, #1, r0, c0, c0, #1 @ read clid register
|
||||
ands r3, r0, #0x7000000 @ get level of coherency
|
||||
mov r3, r3, lsr #23
|
||||
beq finished
|
||||
mov r10, #0
|
||||
loop1:
|
||||
add r2, r10, r10, lsr #1
|
||||
mov r1, r0, lsr r2
|
||||
and r1, r1, #7
|
||||
cmp r1, #2
|
||||
blt skip
|
||||
mcr p15, #2, r10, c0, c0, #0
|
||||
isb
|
||||
mrc p15, #1, r1, c0, c0, #0
|
||||
and r2, r1, #7
|
||||
add r2, r2, #4
|
||||
ldr r4, _FLD_MAX_WAY
|
||||
ands r4, r4, r1, lsr #3
|
||||
clz r5, r4
|
||||
ldr r7, _FLD_MAX_IDX
|
||||
ands r7, r7, r1, lsr #13
|
||||
loop2:
|
||||
mov r9, r4
|
||||
loop3:
|
||||
orr r11, r10, r9, lsl r5
|
||||
orr r11, r11, r7, lsl r2
|
||||
mcr p15, #0, r11, c7, c14, #2
|
||||
subs r9, r9, #1
|
||||
bge loop3
|
||||
subs r7, r7, #1
|
||||
bge loop2
|
||||
skip:
|
||||
add r10, r10, #2
|
||||
cmp r3, r10
|
||||
bgt loop1
|
||||
|
||||
finished:
|
||||
dsb
|
||||
isb
|
||||
pop {r4-r11}
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_icache_flush
|
||||
rt_cpu_icache_flush:
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_dcache_disable
|
||||
rt_hw_cpu_dcache_disable:
|
||||
push {r4-r11, lr}
|
||||
bl rt_cpu_dcache_clean_flush
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #0x00000004
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
pop {r4-r11, lr}
|
||||
bx lr
|
||||
|
||||
.globl rt_hw_cpu_icache_disable
|
||||
rt_hw_cpu_icache_disable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #0x00001000
|
||||
mcr p15, #0, r0, c1, c0, #0
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_mmu_disable
|
||||
rt_cpu_mmu_disable:
|
||||
mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
bic r0, r0, #1
|
||||
mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_mmu_enable
|
||||
rt_cpu_mmu_enable:
|
||||
mrc p15, #0, r0, c1, c0, #0
|
||||
orr r0, r0, #0x001
|
||||
mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit
|
||||
dsb
|
||||
bx lr
|
||||
|
||||
.globl rt_cpu_tlb_set
|
||||
rt_cpu_tlb_set:
|
||||
mcr p15, #0, r0, c2, c0, #0
|
||||
dmb
|
||||
bx lr
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-15 Bernard first version
|
||||
* 2018-11-22 Jesven add rt_hw_cpu_id()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
|
||||
void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
lock->slock = 0;
|
||||
}
|
||||
|
||||
void rt_hw_spin_lock(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
unsigned long tmp;
|
||||
unsigned long newval;
|
||||
rt_hw_spinlock_t lockval;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"pld [%0]"
|
||||
::"r"(&lock->slock)
|
||||
);
|
||||
|
||||
__asm__ __volatile__(
|
||||
"1: ldrex %0, [%3]\n"
|
||||
" add %1, %0, %4\n"
|
||||
" strex %2, %1, [%3]\n"
|
||||
" teq %2, #0\n"
|
||||
" bne 1b"
|
||||
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
|
||||
: "r" (&lock->slock), "I" (1 << 16)
|
||||
: "cc");
|
||||
|
||||
while (lockval.tickets.next != lockval.tickets.owner) {
|
||||
__asm__ __volatile__("wfe":::"memory");
|
||||
lockval.tickets.owner = *(volatile unsigned short *)(&lock->tickets.owner);
|
||||
}
|
||||
|
||||
__asm__ volatile ("dmb":::"memory");
|
||||
}
|
||||
|
||||
void rt_hw_spin_unlock(rt_hw_spinlock_t *lock)
|
||||
{
|
||||
__asm__ volatile ("dmb":::"memory");
|
||||
lock->tickets.owner++;
|
||||
__asm__ volatile ("dsb ishst\nsev":::"memory");
|
||||
}
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
/**
|
||||
* @addtogroup ARM CPU
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/** shutdown CPU */
|
||||
RT_WEAK void rt_hw_cpu_shutdown()
|
||||
{
|
||||
rt_uint32_t level;
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (level)
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
* 2014-04-03 Grissiom many enhancements
|
||||
* 2018-11-22 Jesven add rt_hw_ipi_send()
|
||||
* add rt_hw_ipi_handler_install()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "gic.h"
|
||||
#include "cp15.h"
|
||||
|
||||
struct arm_gic
|
||||
{
|
||||
rt_uint32_t offset; /* the first interrupt index in the vector table */
|
||||
|
||||
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
|
||||
rt_uint32_t cpu_hw_base; /* the base addrees of the gic cpu interface */
|
||||
};
|
||||
|
||||
/* 'ARM_GIC_MAX_NR' is the number of cores */
|
||||
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Interface (GICC)
|
||||
*/
|
||||
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
|
||||
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
|
||||
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
|
||||
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
|
||||
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
|
||||
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
|
||||
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
|
||||
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
|
||||
*/
|
||||
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
|
||||
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
|
||||
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
|
||||
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
|
||||
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
|
||||
|
||||
static unsigned int _gic_max_irq;
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint32_t index)
|
||||
{
|
||||
int irq;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base);
|
||||
irq += _gic_table[index].offset;
|
||||
return irq;
|
||||
}
|
||||
|
||||
void arm_gic_ack(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
|
||||
}
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
void arm_gic_umask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pend;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
/* No CPU identification offered */
|
||||
if (pend != 0U)
|
||||
{
|
||||
pend = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
pend = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return (pend);
|
||||
}
|
||||
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
/* Forward the interrupt to the CPU interface that requested it */
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
mask = 1U << (irq % 32U);
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = 1U << ((irq % 4U) * 8U);
|
||||
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, uint32_t config)
|
||||
{
|
||||
rt_uint32_t icfgr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 16U) << 1U;
|
||||
|
||||
icfgr &= (~(3U << shift));
|
||||
icfgr |= (config << shift);
|
||||
|
||||
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
|
||||
}
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
/* Set up the cpu mask for the specific interrupt */
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
|
||||
{
|
||||
rt_uint32_t old_tgt;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
|
||||
|
||||
old_tgt &= ~(0x0FFUL << ((irq % 4U)*8U));
|
||||
old_tgt |= cpumask << ((irq % 4U)*8U);
|
||||
|
||||
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
|
||||
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
|
||||
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
|
||||
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
/* set priority mask */
|
||||
GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
|
||||
{
|
||||
GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
|
||||
{
|
||||
return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pending;
|
||||
rt_uint32_t active;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
|
||||
return ((active << 1U) | pending);
|
||||
}
|
||||
|
||||
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
|
||||
{
|
||||
uint32_t igroupr;
|
||||
uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(group <= 1U);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 32U);
|
||||
igroupr &= (~(1U << shift));
|
||||
igroupr |= ( (group & 0x1U) << shift);
|
||||
|
||||
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
|
||||
{
|
||||
unsigned int gic_type, i;
|
||||
rt_uint32_t cpumask = 1U << 0U;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].dist_hw_base = dist_base;
|
||||
_gic_table[index].offset = irq_start;
|
||||
|
||||
/* Find out how many interrupts are supported. */
|
||||
gic_type = GIC_DIST_TYPE(dist_base);
|
||||
_gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
|
||||
|
||||
/*
|
||||
* The GIC only supports up to 1020 interrupt sources.
|
||||
* Limit this to either the architected maximum, or the
|
||||
* platform maximum.
|
||||
*/
|
||||
if (_gic_max_irq > 1020U)
|
||||
_gic_max_irq = 1020U;
|
||||
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
|
||||
_gic_max_irq = ARM_GIC_NR_IRQS;
|
||||
|
||||
cpumask |= cpumask << 8U;
|
||||
cpumask |= cpumask << 16U;
|
||||
cpumask |= cpumask << 24U;
|
||||
|
||||
GIC_DIST_CTRL(dist_base) = 0x0U;
|
||||
|
||||
/* Set all global interrupts to be level triggered, active low. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 16U)
|
||||
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
|
||||
|
||||
/* Set all global interrupts to this CPU only. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 4U)
|
||||
GIC_DIST_TARGET(dist_base, i) = cpumask;
|
||||
|
||||
/* Set priority on all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 4U)
|
||||
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
|
||||
|
||||
/* Disable all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
|
||||
|
||||
#if 0
|
||||
/* All interrupts defaults to IGROUP1(IRQ). */
|
||||
for (i = 0; i < _gic_max_irq; i += 32)
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0xffffffff;
|
||||
#endif
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0U;
|
||||
|
||||
/* Enable group0 and group1 interrupt forwarding. */
|
||||
GIC_DIST_CTRL(dist_base) = 0x01U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].cpu_hw_base = cpu_base;
|
||||
|
||||
GIC_CPU_PRIMASK(cpu_base) = 0xf0U;
|
||||
GIC_CPU_BINPOINT(cpu_base) = 0x7U;
|
||||
/* Enable CPU interrupt */
|
||||
GIC_CPU_CTRL(cpu_base) = 0x01U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index)
|
||||
{
|
||||
unsigned int gic_type;
|
||||
|
||||
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
|
||||
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
|
||||
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
|
||||
_gic_table[index].dist_hw_base,
|
||||
_gic_max_irq,
|
||||
gic_type & (1U << 10U) ? "has" : "no",
|
||||
gic_type);
|
||||
}
|
||||
|
||||
void arm_gic_dump(rt_uint32_t index)
|
||||
{
|
||||
unsigned int i, k;
|
||||
|
||||
k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
||||
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
|
||||
rt_kprintf("--- hw mask ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw pending ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw active ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
long gic_dump(void)
|
||||
{
|
||||
arm_gic_dump_type(0);
|
||||
arm_gic_dump(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(gic_dump, show gic status);
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __GIC_H__
|
||||
#define __GIC_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint32_t index);
|
||||
void arm_gic_ack(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq);
|
||||
void arm_gic_umask(rt_uint32_t index, int irq);
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, uint32_t config);
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list);
|
||||
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
|
||||
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start);
|
||||
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base);
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index);
|
||||
void arm_gic_dump(rt_uint32_t index);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,708 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
* 2014-04-03 Grissiom many enhancements
|
||||
* 2018-11-22 Jesven add rt_hw_ipi_send()
|
||||
* add rt_hw_ipi_handler_install()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "gicv3.h"
|
||||
#include "cp15.h"
|
||||
|
||||
#ifndef RT_CPUS_NR
|
||||
#define RT_CPUS_NR 1
|
||||
#endif
|
||||
|
||||
struct arm_gic_v3
|
||||
{
|
||||
rt_uint32_t offset; /* the first interrupt index in the vector table */
|
||||
rt_uint32_t redist_hw_base[RT_CPUS_NR]; /* the pointer of the gic redistributor */
|
||||
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
|
||||
rt_uint32_t cpu_hw_base[RT_CPUS_NR]; /* the base addrees of the gic cpu interface */
|
||||
};
|
||||
|
||||
/* 'ARM_GIC_MAX_NR' is the number of cores */
|
||||
static struct arm_gic_v3 _gic_table[ARM_GIC_MAX_NR];
|
||||
static unsigned int _gic_max_irq;
|
||||
|
||||
/**
|
||||
* @name: arm_gic_cpumask_to_affval
|
||||
* @msg:
|
||||
* @in param cpu_mask:
|
||||
* @out param cluster_id: aff1 [0:7],aff2 [8:15],aff3 [16:23]
|
||||
* @out param target_list: Target List. The set of PEs for which SGI interrupts will be generated. Each bit corresponds to the
|
||||
* PE within a cluster with an Affinity 0 value equal to the bit number.
|
||||
* @return {rt_uint32_t} 0 is finish , 1 is data valid
|
||||
*/
|
||||
RT_WEAK rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RT_WEAK rt_uint64_t get_main_cpu_affval(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_get_active_irq(rt_uint32_t index)
|
||||
{
|
||||
int irq;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
__get_gicv3_reg(ICC_IAR1, irq);
|
||||
|
||||
irq = (irq & 0x1FFFFFF) + _gic_table[index].offset;
|
||||
return irq;
|
||||
}
|
||||
|
||||
void arm_gic_ack(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
__asm__ volatile("dsb 0xF" ::
|
||||
: "memory");
|
||||
__set_gicv3_reg(ICC_EOIR1, irq);
|
||||
}
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
GIC_RDISTSGI_ICENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_umask(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
GIC_RDISTSGI_ISENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pend;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
/* No CPU identification offered */
|
||||
if (pend != 0U)
|
||||
{
|
||||
pend = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
pend = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return (pend);
|
||||
}
|
||||
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTID 0-15 Software Generated Interrupt */
|
||||
/* Forward the interrupt to the CPU interface that requested it */
|
||||
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq >= 16U)
|
||||
{
|
||||
mask = 1U << (irq % 32U);
|
||||
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = 1U << ((irq % 4U) * 8U);
|
||||
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
|
||||
{
|
||||
rt_uint32_t icfgr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 16U) << 1U;
|
||||
|
||||
icfgr &= (~(3U << shift));
|
||||
icfgr |= (config << shift);
|
||||
|
||||
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
|
||||
}
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t mask = 1U << (irq % 32U);
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
|
||||
/* Set up the cpu mask for the specific interrupt */
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
|
||||
{
|
||||
rt_uint32_t old_tgt;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
|
||||
|
||||
old_tgt &= ~(0x0FFUL << ((irq % 4U) * 8U));
|
||||
old_tgt |= cpumask << ((irq % 4U) * 8U);
|
||||
|
||||
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
|
||||
{
|
||||
rt_uint32_t mask;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
|
||||
mask = GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq);
|
||||
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
|
||||
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
|
||||
GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) = mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
|
||||
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
|
||||
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
|
||||
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
if (irq < 32U)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
return (GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
value &= 0xFFUL;
|
||||
/* set priority mask */
|
||||
__set_gicv3_reg(ICC_SRE, value);
|
||||
__asm__ volatile ("isb 0xF"::
|
||||
:"memory");
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
rt_uint32_t value;
|
||||
|
||||
__get_gicv3_reg(ICC_SRE, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
priority &= 0xFFUL;
|
||||
/* set priority mask */
|
||||
__set_gicv3_reg(ICC_PMR, priority);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
rt_uint32_t priority;
|
||||
|
||||
__get_gicv3_reg(ICC_PMR, priority);
|
||||
return priority;
|
||||
}
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
|
||||
{
|
||||
index = index;
|
||||
binary_point &= 0x7U;
|
||||
|
||||
__set_gicv3_reg(ICC_BPR1, binary_point);
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
|
||||
{
|
||||
rt_uint32_t binary_point;
|
||||
|
||||
index = index;
|
||||
__get_gicv3_reg(ICC_BPR1, binary_point);
|
||||
return binary_point;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
||||
{
|
||||
rt_uint32_t pending;
|
||||
rt_uint32_t active;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
|
||||
return ((active << 1U) | pending);
|
||||
}
|
||||
|
||||
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode)
|
||||
{
|
||||
rt_uint64_t sgi_val;
|
||||
|
||||
if (routing_mode)
|
||||
{
|
||||
sgi_val = (1ULL << 40) | ((irq & 0x0FULL) << 24); //Interrupts routed to all PEs in the system, excluding "self".
|
||||
/* Write the ICC_SGI1R registers */
|
||||
__asm__ volatile("dsb 0xF" ::
|
||||
: "memory");
|
||||
__set_cp64(15, 0, sgi_val, 12);
|
||||
__asm__ volatile("isb 0xF" ::
|
||||
: "memory");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_uint32_t cluster_id, target_list;
|
||||
while (arm_gic_cpumask_to_affval(&cpu_mask, &cluster_id, &target_list))
|
||||
{
|
||||
sgi_val = ((irq & 0x0FULL) << 24 |
|
||||
target_list |
|
||||
((cluster_id >> 8) & 0xFFULL) << GIC_RSGI_AFF1_OFFSET |
|
||||
((cluster_id >> 16) & 0xFFULL) << GIC_RSGI_AFF2_OFFSET |
|
||||
((cluster_id >> 24) & 0xFFull) << GIC_RSGI_AFF3_OFFSET);
|
||||
|
||||
__asm__ volatile("dsb 0xF" ::
|
||||
: "memory");
|
||||
__set_cp64(15, 0, sgi_val, 12);
|
||||
__asm__ volatile("isb 0xF" ::
|
||||
: "memory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
|
||||
{
|
||||
rt_uint32_t irq;
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
index = index;
|
||||
__get_gicv3_reg(ICC_HPPIR1, irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
||||
}
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
|
||||
{
|
||||
rt_uint32_t igroupr;
|
||||
rt_uint32_t shift;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT(group <= 1U);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
|
||||
shift = (irq % 32U);
|
||||
igroupr &= (~(1U << shift));
|
||||
igroupr |= ((group & 0x1U) << shift);
|
||||
|
||||
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
||||
}
|
||||
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
irq = irq - _gic_table[index].offset;
|
||||
RT_ASSERT(irq >= 0U);
|
||||
|
||||
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
||||
}
|
||||
|
||||
static int arm_gicv3_wait_rwp(rt_uint32_t index, rt_uint32_t irq)
|
||||
{
|
||||
rt_uint32_t rwp_bit;
|
||||
rt_uint32_t base;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
if (irq < 32u)
|
||||
{
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
base = _gic_table[index].redist_hw_base[cpu_id];
|
||||
rwp_bit = GICR_CTLR_RWP;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = _gic_table[index].dist_hw_base;
|
||||
rwp_bit = GICD_CTLR_RWP;
|
||||
}
|
||||
|
||||
while (__REG32(base) & rwp_bit)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
|
||||
{
|
||||
rt_uint64_t cpu0_affval;
|
||||
unsigned int gic_type, i;
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
_gic_table[index].dist_hw_base = dist_base;
|
||||
_gic_table[index].offset = irq_start;
|
||||
|
||||
/* Find out how many interrupts are supported. */
|
||||
gic_type = GIC_DIST_TYPE(dist_base);
|
||||
_gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
|
||||
|
||||
/*
|
||||
* The GIC only supports up to 1020 interrupt sources.
|
||||
* Limit this to either the architected maximum, or the
|
||||
* platform maximum.
|
||||
*/
|
||||
if (_gic_max_irq > 1020U)
|
||||
_gic_max_irq = 1020U;
|
||||
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
|
||||
_gic_max_irq = ARM_GIC_NR_IRQS;
|
||||
|
||||
GIC_DIST_CTRL(dist_base) = 0x0U;
|
||||
/* Wait for register write pending */
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/* Set all global interrupts to be level triggered, active low. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 16U)
|
||||
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
cpu0_affval = get_main_cpu_affval();
|
||||
/* Set all global interrupts to this CPU only. */
|
||||
for (i = 32U; i < _gic_max_irq; i++)
|
||||
{
|
||||
GIC_DIST_IROUTER_LOW(dist_base, i) = cpu0_affval;
|
||||
GIC_DIST_IROUTER_HIGH(dist_base, i) = cpu0_affval >> 32;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/* Set priority on spi interrupts. */
|
||||
for (i = 32U; i < _gic_max_irq; i += 4U)
|
||||
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
/* Disable all interrupts. */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
{
|
||||
GIC_DIST_PENDING_CLEAR(dist_base, i) = 0xffffffffU;
|
||||
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
|
||||
}
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
/* All interrupts defaults to IGROUP1(IRQ). */
|
||||
for (i = 0U; i < _gic_max_irq; i += 32U)
|
||||
GIC_DIST_IGROUP(dist_base, i) = 0xffffffffU;
|
||||
|
||||
arm_gicv3_wait_rwp(0, 32);
|
||||
|
||||
/*
|
||||
The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode.
|
||||
Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled.
|
||||
If affinity routing is not enabled, GICv3 can be configured for legacy operation.
|
||||
Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state.
|
||||
Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
|
||||
GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts.
|
||||
GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
|
||||
GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts.
|
||||
*/
|
||||
GIC_DIST_CTRL(dist_base) = GICD_CTLR_ARE_NS | GICD_CTLR_ENGRP1NS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
_gic_table[index].redist_hw_base[cpu_id] = redist_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id)
|
||||
{
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
_gic_table[index].cpu_hw_base[cpu_id] = interface_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_redist_init(rt_uint32_t index)
|
||||
{
|
||||
unsigned int i;
|
||||
rt_uint32_t base;
|
||||
rt_int32_t cpu_id = rt_hw_cpu_id();
|
||||
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
RT_ASSERT((cpu_id) < RT_CPUS_NR);
|
||||
|
||||
base = _gic_table[index].redist_hw_base[cpu_id];
|
||||
/* redistributor enable */
|
||||
GIC_RDIST_WAKER(base) &= ~(1U << 1);
|
||||
while (GIC_RDIST_WAKER(base) & (1 << 2))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* Disable all sgi and ppi interrupt */
|
||||
GIC_RDISTSGI_ICENABLER0(base) = 0xFFFFFFFF;
|
||||
arm_gicv3_wait_rwp(0, 0);
|
||||
|
||||
/* Clear all inetrrupt pending */
|
||||
GIC_RDISTSGI_ICPENDR0(base) = 0xFFFFFFFF;
|
||||
|
||||
/* the corresponding interrupt is Group 1 or Non-secure Group 1. */
|
||||
GIC_RDISTSGI_IGROUPR0(base, 0) = 0xFFFFFFFF;
|
||||
GIC_RDISTSGI_IGRPMODR0(base, 0) = 0xFFFFFFFF;
|
||||
|
||||
/* Configure default priorities for SGI 0:15 and PPI 16:31. */
|
||||
for (i = 0; i < 32; i += 4)
|
||||
{
|
||||
GIC_RDISTSGI_IPRIORITYR(base, i) = 0xa0a0a0a0U;
|
||||
}
|
||||
|
||||
/* Trigger level for PPI interrupts*/
|
||||
GIC_RDISTSGI_ICFGR1(base) = 0x0U; // PPI is level-sensitive.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_gic_cpu_init(rt_uint32_t index)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
||||
|
||||
value = arm_gic_get_system_register_enable_mask(index);
|
||||
value |= (1U << 0);
|
||||
arm_gic_set_system_register_enable_mask(index, value);
|
||||
__set_gicv3_reg(ICC_CTLR, 0);
|
||||
|
||||
arm_gic_set_interface_prior_mask(index, 0xFFU);
|
||||
|
||||
/* Enable group1 interrupt */
|
||||
value = 0x1U;
|
||||
__set_gicv3_reg(ICC_IGRPEN1, value);
|
||||
|
||||
arm_gic_set_binary_point(0, 0);
|
||||
|
||||
/* ICC_BPR0_EL1 determines the preemption group for both
|
||||
Group 0 and Group 1 interrupts.
|
||||
*/
|
||||
value = 0x1U;
|
||||
__set_gicv3_reg(ICC_CTLR, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void arm_gic_secondary_cpu_init(void)
|
||||
{
|
||||
arm_gic_redist_init(0);
|
||||
|
||||
arm_gic_cpu_init(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index)
|
||||
{
|
||||
unsigned int gic_type;
|
||||
|
||||
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
|
||||
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
|
||||
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
|
||||
_gic_table[index].dist_hw_base,
|
||||
_gic_max_irq,
|
||||
gic_type & (1U << 10U) ? "has" : "no",
|
||||
gic_type);
|
||||
}
|
||||
|
||||
void arm_gic_dump(rt_uint32_t index)
|
||||
{
|
||||
unsigned int i, k;
|
||||
|
||||
k = arm_gic_get_high_pending_irq(0);
|
||||
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
|
||||
rt_kprintf("--- hw mask ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw pending ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n--- hw active ---\n");
|
||||
for (i = 0U; i < _gic_max_irq / 32U; i++)
|
||||
{
|
||||
rt_kprintf("0x%08x, ",
|
||||
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
|
||||
i * 32U));
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
long gic_dump(void)
|
||||
{
|
||||
arm_gic_dump_type(0);
|
||||
arm_gic_dump(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(gic_dump, show gic status);
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __GIC_V3_H__
|
||||
#define __GIC_V3_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#define __get_gicv3_reg(CR, Rt) __asm__ volatile("MRC " CR \
|
||||
: "=r"(Rt) \
|
||||
: \
|
||||
: "memory")
|
||||
#define __set_gicv3_reg(CR, Rt) __asm__ volatile("MCR " CR \
|
||||
: \
|
||||
: "r"(Rt) \
|
||||
: "memory")
|
||||
|
||||
|
||||
/* AArch32 System register interface to GICv3 */
|
||||
#define ICC_IAR0 "p15, 0, %0, c12, c8, 0"
|
||||
#define ICC_IAR1 "p15, 0, %0, c12, c12, 0"
|
||||
#define ICC_EOIR0 "p15, 0, %0, c12, c8, 1"
|
||||
#define ICC_EOIR1 "p15, 0, %0, c12, c12, 1"
|
||||
#define ICC_HPPIR0 "p15, 0, %0, c12, c8, 2"
|
||||
#define ICC_HPPIR1 "p15, 0, %0, c12, c12, 2"
|
||||
#define ICC_BPR0 "p15, 0, %0, c12, c8, 3"
|
||||
#define ICC_BPR1 "p15, 0, %0, c12, c12, 3"
|
||||
#define ICC_DIR "p15, 0, %0, c12, c11, 1"
|
||||
#define ICC_PMR "p15, 0, %0, c4, c6, 0"
|
||||
#define ICC_RPR "p15, 0, %0, c12, c11, 3"
|
||||
#define ICC_CTLR "p15, 0, %0, c12, c12, 4"
|
||||
#define ICC_MCTLR "p15, 6, %0, c12, c12, 4"
|
||||
#define ICC_SRE "p15, 0, %0, c12, c12, 5"
|
||||
#define ICC_HSRE "p15, 4, %0, c12, c9, 5"
|
||||
#define ICC_MSRE "p15, 6, %0, c12, c12, 5"
|
||||
#define ICC_IGRPEN0 "p15, 0, %0, c12, c12, 6"
|
||||
#define ICC_IGRPEN1 "p15, 0, %0, c12, c12, 7"
|
||||
#define ICC_MGRPEN1 "p15, 6, %0, c12, c12, 7"
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_uint32_t)x)))
|
||||
|
||||
#define ROUTED_TO_ALL (1)
|
||||
#define ROUTED_TO_SPEC (0)
|
||||
|
||||
/** Macro to access the Distributor Control Register (GICD_CTLR)
|
||||
*/
|
||||
#define GICD_CTLR_RWP (1<<31)
|
||||
#define GICD_CTLR_E1NWF (1<<7)
|
||||
#define GICD_CTLR_DS (1<<6)
|
||||
#define GICD_CTLR_ARE_NS (1<<5)
|
||||
#define GICD_CTLR_ARE_S (1<<4)
|
||||
#define GICD_CTLR_ENGRP1S (1<<2)
|
||||
#define GICD_CTLR_ENGRP1NS (1<<1)
|
||||
#define GICD_CTLR_ENGRP0 (1<<0)
|
||||
|
||||
/** Macro to access the Redistributor Control Register (GICR_CTLR)
|
||||
*/
|
||||
#define GICR_CTLR_UWP (1<<31)
|
||||
#define GICR_CTLR_DPG1S (1<<26)
|
||||
#define GICR_CTLR_DPG1NS (1<<25)
|
||||
#define GICR_CTLR_DPG0 (1<<24)
|
||||
#define GICR_CTLR_RWP (1<<3)
|
||||
#define GICR_CTLR_IR (1<<2)
|
||||
#define GICR_CTLR_CES (1<<1)
|
||||
#define GICR_CTLR_EnableLPI (1<<0)
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Interface (GICC)
|
||||
*/
|
||||
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
|
||||
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
|
||||
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
|
||||
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
|
||||
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
|
||||
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
|
||||
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
|
||||
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
|
||||
*/
|
||||
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
|
||||
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
|
||||
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
|
||||
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
|
||||
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
|
||||
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
|
||||
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
|
||||
#define GIC_DIST_IROUTER_LOW(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U)
|
||||
#define GIC_DIST_IROUTER_HIGH(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U + 4)
|
||||
|
||||
/* SGI base address is at 64K offset from Redistributor base address */
|
||||
#define GIC_RSGI_OFFSET 0x10000
|
||||
|
||||
/** Macro to access the Generic Interrupt Controller Redistributor (GICD)
|
||||
*/
|
||||
#define GIC_RDIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
|
||||
#define GIC_RDIST_IIDR(hw_base) __REG32((hw_base) + 0x004U)
|
||||
#define GIC_RDIST_TYPER(hw_base) __REG32((hw_base) + 0x008U)
|
||||
#define GIC_RDIST_TSTATUSR(hw_base) __REG32((hw_base) + 0x010U)
|
||||
#define GIC_RDIST_WAKER(hw_base) __REG32((hw_base) + 0x014U)
|
||||
#define GIC_RDIST_SETLPIR(hw_base) __REG32((hw_base) + 0x040U)
|
||||
#define GIC_RDIST_CLRLPIR(hw_base) __REG32((hw_base) + 0x048U)
|
||||
#define GIC_RDIST_PROPBASER(hw_base) __REG32((hw_base) + 0x070U)
|
||||
#define GIC_RDIST_PENDBASER(hw_base) __REG32((hw_base) + 0x078U)
|
||||
#define GIC_RDIST_INVLPIR(hw_base) __REG32((hw_base) + 0x0A0U)
|
||||
#define GIC_RDIST_INVALLR(hw_base) __REG32((hw_base) + 0x0B0U)
|
||||
#define GIC_RDIST_SYNCR(hw_base) __REG32((hw_base) + 0x0C0U)
|
||||
|
||||
#define GIC_RDISTSGI_IGROUPR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x080U + (n)*4U)
|
||||
#define GIC_RDISTSGI_ISENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x100U)
|
||||
#define GIC_RDISTSGI_ICENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x180U)
|
||||
#define GIC_RDISTSGI_ISPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x200U)
|
||||
#define GIC_RDISTSGI_ICPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x280U)
|
||||
#define GIC_RDISTSGI_ISACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x300U)
|
||||
#define GIC_RDISTSGI_ICACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x380U)
|
||||
#define GIC_RDISTSGI_IPRIORITYR(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x400U + ((n) / 4U) * 4U)
|
||||
#define GIC_RDISTSGI_ICFGR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC00U)
|
||||
#define GIC_RDISTSGI_ICFGR1(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC04U)
|
||||
#define GIC_RDISTSGI_IGRPMODR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xD00U + (n)*4)
|
||||
#define GIC_RDISTSGI_NSACR(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xE00U)
|
||||
|
||||
#define GIC_RSGI_AFF1_OFFSET 16
|
||||
#define GIC_RSGI_AFF2_OFFSET 32
|
||||
#define GIC_RSGI_AFF3_OFFSET 48
|
||||
|
||||
rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list);
|
||||
rt_uint64_t get_main_cpu_affval(void);
|
||||
int arm_gic_get_active_irq(rt_uint32_t index);
|
||||
void arm_gic_ack(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_mask(rt_uint32_t index, int irq);
|
||||
void arm_gic_umask(rt_uint32_t index, int irq);
|
||||
|
||||
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
|
||||
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config);
|
||||
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_clear_active(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
|
||||
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
|
||||
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
|
||||
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
|
||||
|
||||
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode);
|
||||
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
|
||||
|
||||
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
|
||||
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
|
||||
|
||||
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id);
|
||||
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id);
|
||||
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start);
|
||||
int arm_gic_cpu_init(rt_uint32_t index);
|
||||
int arm_gic_redist_init(rt_uint32_t index);
|
||||
|
||||
void arm_gic_dump_type(rt_uint32_t index);
|
||||
void arm_gic_dump(rt_uint32_t index);
|
||||
|
||||
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value);
|
||||
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index);
|
||||
void arm_gic_secondary_cpu_init(void);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
* 2018-11-22 Jesven add smp support
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include "interrupt.h"
|
||||
|
||||
#ifdef RT_USING_GIC_V2
|
||||
#include "gic.h"
|
||||
#else
|
||||
#include "gicv3.h"
|
||||
#endif
|
||||
|
||||
/* exception and interrupt handler table */
|
||||
struct rt_irq_desc isr_table[MAX_HANDLERS];
|
||||
|
||||
#ifndef RT_USING_SMP
|
||||
/* Those varibles will be accessed in ISR, so we need to share them. */
|
||||
rt_uint32_t rt_interrupt_from_thread = 0;
|
||||
rt_uint32_t rt_interrupt_to_thread = 0;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag = 0;
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
static void (*rt_interrupt_switch_hook)(void);
|
||||
|
||||
void rt_interrupt_switch_sethook(void (*hook)(void))
|
||||
{
|
||||
rt_interrupt_switch_hook = hook;
|
||||
}
|
||||
#endif
|
||||
|
||||
void rt_interrupt_hook(void)
|
||||
{
|
||||
RT_OBJECT_HOOK_CALL(rt_interrupt_switch_hook, ());
|
||||
}
|
||||
#endif
|
||||
|
||||
const unsigned int VECTOR_BASE = 0x00;
|
||||
extern void rt_cpu_vector_set_base(unsigned int addr);
|
||||
extern int system_vectors;
|
||||
|
||||
void rt_hw_vector_init(void)
|
||||
{
|
||||
rt_cpu_vector_set_base((unsigned int)&system_vectors);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_GIC_V2
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
rt_uint32_t gic_cpu_base;
|
||||
rt_uint32_t gic_dist_base;
|
||||
rt_uint32_t gic_irq_start;
|
||||
|
||||
/* initialize vector table */
|
||||
rt_hw_vector_init();
|
||||
|
||||
/* initialize exceptions table */
|
||||
rt_memset(isr_table, 0x00, sizeof(isr_table));
|
||||
|
||||
/* initialize ARM GIC */
|
||||
gic_dist_base = platform_get_gic_dist_base();
|
||||
gic_cpu_base = platform_get_gic_cpu_base();
|
||||
|
||||
gic_irq_start = GIC_IRQ_START;
|
||||
|
||||
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
|
||||
arm_gic_cpu_init(0, gic_cpu_base);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
* Called by the primary cpu(cpu0)
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
rt_uint32_t gic_dist_base;
|
||||
rt_uint32_t gic_irq_start;
|
||||
|
||||
/* initialize vector table */
|
||||
rt_hw_vector_init();
|
||||
|
||||
/* initialize exceptions table */
|
||||
rt_memset(isr_table, 0x00, sizeof(isr_table));
|
||||
|
||||
/* initialize ARM GIC */
|
||||
gic_dist_base = platform_get_gic_dist_base();
|
||||
gic_irq_start = GIC_IRQ_START;
|
||||
|
||||
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
|
||||
|
||||
arm_gic_cpu_init(0);
|
||||
arm_gic_redist_init(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_mask(int vector)
|
||||
{
|
||||
arm_gic_mask(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will un-mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
arm_gic_umask(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the active interrupt number.
|
||||
* @param none
|
||||
*/
|
||||
int rt_hw_interrupt_get_irq(void)
|
||||
{
|
||||
return arm_gic_get_active_irq(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function acknowledges the interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_ack(int vector)
|
||||
{
|
||||
arm_gic_ack(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt CPU targets.
|
||||
* @param vector: the interrupt number
|
||||
* cpu_mask: target cpus mask, one bit for one core
|
||||
*/
|
||||
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask)
|
||||
{
|
||||
arm_gic_set_cpu(0, vector, cpu_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt CPU targets.
|
||||
* @param vector: the interrupt number
|
||||
* @return target cpus mask, one bit for one core
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_target_cpus(int vector)
|
||||
{
|
||||
return arm_gic_get_target_cpu(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt triger mode.
|
||||
* @param vector: the interrupt number
|
||||
* mode: interrupt triger mode; 0: level triger, 1: edge triger
|
||||
*/
|
||||
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode)
|
||||
{
|
||||
arm_gic_set_configuration(0, vector, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt triger mode.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt triger mode; 0: level triger, 1: edge triger
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_triger_mode(int vector)
|
||||
{
|
||||
return arm_gic_get_configuration(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_set_pending(int vector)
|
||||
{
|
||||
arm_gic_set_pending_irq(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt pending flag, 0: not pending; 1: pending
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_pending(int vector)
|
||||
{
|
||||
return arm_gic_get_pending_irq(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function clear interrupt pending flag.
|
||||
* @param vector: the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_clear_pending(int vector)
|
||||
{
|
||||
arm_gic_clear_pending_irq(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set interrupt priority value.
|
||||
* @param vector: the interrupt number
|
||||
* priority: the priority of interrupt to set
|
||||
*/
|
||||
void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
|
||||
{
|
||||
arm_gic_set_priority(0, vector, priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get interrupt priority.
|
||||
* @param vector: the interrupt number
|
||||
* @return interrupt priority value
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_priority(int vector)
|
||||
{
|
||||
return arm_gic_get_priority(0, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set priority masking threshold.
|
||||
* @param priority: priority masking threshold
|
||||
*/
|
||||
void rt_hw_interrupt_set_priority_mask(unsigned int priority)
|
||||
{
|
||||
arm_gic_set_interface_prior_mask(0, priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get priority masking threshold.
|
||||
* @param none
|
||||
* @return priority masking threshold
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_priority_mask(void)
|
||||
{
|
||||
return arm_gic_get_interface_prior_mask(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set priority grouping field split point.
|
||||
* @param bits: priority grouping field split point
|
||||
* @return 0: success; -1: failed
|
||||
*/
|
||||
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (bits < 8)
|
||||
{
|
||||
arm_gic_set_binary_point(0, (7 - bits));
|
||||
status = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get priority grouping field split point.
|
||||
* @param none
|
||||
* @return priority grouping field split point
|
||||
*/
|
||||
unsigned int rt_hw_interrupt_get_prior_group_bits(void)
|
||||
{
|
||||
unsigned int bp;
|
||||
|
||||
bp = arm_gic_get_binary_point(0) & 0x07;
|
||||
|
||||
return (7 - bp);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param new_handler the interrupt service routine to be installed
|
||||
* @param old_handler the old interrupt service routine
|
||||
*/
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name)
|
||||
{
|
||||
rt_isr_handler_t old_handler = RT_NULL;
|
||||
|
||||
if (vector < MAX_HANDLERS)
|
||||
{
|
||||
old_handler = isr_table[vector].handler;
|
||||
|
||||
if (handler != RT_NULL)
|
||||
{
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
|
||||
#endif /* RT_USING_INTERRUPT_INFO */
|
||||
isr_table[vector].handler = handler;
|
||||
isr_table[vector].param = param;
|
||||
}
|
||||
}
|
||||
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
|
||||
{
|
||||
#ifdef RT_USING_GIC_V2
|
||||
arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0);
|
||||
#else
|
||||
arm_gic_send_affinity_sgi(0, ipi_vector, cpu_mask, ROUTED_TO_SPEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
|
||||
{
|
||||
/* note: ipi_vector maybe different with irq_vector */
|
||||
rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-06 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef __INTERRUPT_H__
|
||||
#define __INTERRUPT_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#define INT_IRQ 0x00
|
||||
#define INT_FIQ 0x01
|
||||
|
||||
#define IRQ_MODE_TRIG_LEVEL (0x00) /* Trigger: level triggered interrupt */
|
||||
#define IRQ_MODE_TRIG_EDGE (0x01) /* Trigger: edge triggered interrupt */
|
||||
|
||||
void rt_hw_vector_init(void);
|
||||
|
||||
void rt_hw_interrupt_init(void);
|
||||
void rt_hw_interrupt_mask(int vector);
|
||||
void rt_hw_interrupt_umask(int vector);
|
||||
|
||||
int rt_hw_interrupt_get_irq(void);
|
||||
void rt_hw_interrupt_ack(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask);
|
||||
unsigned int rt_hw_interrupt_get_target_cpus(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode);
|
||||
unsigned int rt_hw_interrupt_get_triger_mode(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_pending(int vector);
|
||||
unsigned int rt_hw_interrupt_get_pending(int vector);
|
||||
void rt_hw_interrupt_clear_pending(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_priority(int vector, unsigned int priority);
|
||||
unsigned int rt_hw_interrupt_get_priority(int vector);
|
||||
|
||||
void rt_hw_interrupt_set_priority_mask(unsigned int priority);
|
||||
unsigned int rt_hw_interrupt_get_priority_mask(void);
|
||||
|
||||
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits);
|
||||
unsigned int rt_hw_interrupt_get_prior_group_bits(void);
|
||||
|
||||
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
|
||||
void *param, const char *name);
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask);
|
||||
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-10 bernard porting to AM1808
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#include "cp15.h"
|
||||
#include "mmu.h"
|
||||
|
||||
/* dump 2nd level page table */
|
||||
void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb)
|
||||
{
|
||||
int i;
|
||||
int fcnt = 0;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
rt_uint32_t pte2 = ptb[i];
|
||||
if ((pte2 & 0x3) == 0)
|
||||
{
|
||||
if (fcnt == 0)
|
||||
rt_kprintf(" ");
|
||||
rt_kprintf("%04x: ", i);
|
||||
fcnt++;
|
||||
if (fcnt == 16)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (fcnt != 0)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
|
||||
rt_kprintf(" %04x: %x: ", i, pte2);
|
||||
if ((pte2 & 0x3) == 0x1)
|
||||
{
|
||||
rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n",
|
||||
((pte2 >> 7) | (pte2 >> 4))& 0xf,
|
||||
(pte2 >> 15) & 0x1,
|
||||
((pte2 >> 10) | (pte2 >> 2)) & 0x1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n",
|
||||
((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1,
|
||||
((pte2 >> 4) | (pte2 >> 2)) & 0x1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb)
|
||||
{
|
||||
int i;
|
||||
int fcnt = 0;
|
||||
|
||||
rt_kprintf("page table@%p\n", ptb);
|
||||
for (i = 0; i < 1024*4; i++)
|
||||
{
|
||||
rt_uint32_t pte1 = ptb[i];
|
||||
if ((pte1 & 0x3) == 0)
|
||||
{
|
||||
rt_kprintf("%03x: ", i);
|
||||
fcnt++;
|
||||
if (fcnt == 16)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (fcnt != 0)
|
||||
{
|
||||
rt_kprintf("fault\n");
|
||||
fcnt = 0;
|
||||
}
|
||||
|
||||
rt_kprintf("%03x: %08x: ", i, pte1);
|
||||
if ((pte1 & 0x3) == 0x3)
|
||||
{
|
||||
rt_kprintf("LPAE\n");
|
||||
}
|
||||
else if ((pte1 & 0x3) == 0x1)
|
||||
{
|
||||
rt_kprintf("pte,ns:%d,domain:%d\n",
|
||||
(pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf);
|
||||
/*
|
||||
*rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000)
|
||||
* - 0x80000000 + 0xC0000000));
|
||||
*/
|
||||
}
|
||||
else if (pte1 & (1 << 18))
|
||||
{
|
||||
rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n",
|
||||
(pte1 >> 19) & 0x1,
|
||||
((pte1 >> 13) | (pte1 >> 10))& 0xf,
|
||||
(pte1 >> 4) & 0x1,
|
||||
((pte1 >> 10) | (pte1 >> 2)) & 0x1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("section,ns:%d,ap:%x,"
|
||||
"xn:%d,texcb:%02x,domain:%d\n",
|
||||
(pte1 >> 19) & 0x1,
|
||||
((pte1 >> 13) | (pte1 >> 10))& 0xf,
|
||||
(pte1 >> 4) & 0x1,
|
||||
(((pte1 & (0x7 << 12)) >> 10) |
|
||||
((pte1 & 0x0c) >> 2)) & 0x1f,
|
||||
(pte1 >> 5) & 0xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* level1 page table, each entry for 1MB memory. */
|
||||
volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024)));
|
||||
void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart,
|
||||
rt_uint32_t vaddrEnd,
|
||||
rt_uint32_t paddrStart,
|
||||
rt_uint32_t attr)
|
||||
{
|
||||
volatile rt_uint32_t *pTT;
|
||||
volatile int i, nSec;
|
||||
pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20);
|
||||
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
|
||||
for(i = 0; i <= nSec; i++)
|
||||
{
|
||||
*pTT = attr | (((paddrStart >> 20) + i) << 20);
|
||||
pTT++;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long rt_hw_set_domain_register(unsigned long domain_val)
|
||||
{
|
||||
unsigned long old_domain;
|
||||
|
||||
asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
|
||||
asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
|
||||
|
||||
return old_domain;
|
||||
}
|
||||
|
||||
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size)
|
||||
{
|
||||
/* set page table */
|
||||
for(; size > 0; size--)
|
||||
{
|
||||
rt_hw_mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
|
||||
mdesc->paddr_start, mdesc->attr);
|
||||
mdesc++;
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_mmu_init(void)
|
||||
{
|
||||
rt_cpu_dcache_clean_flush();
|
||||
rt_cpu_icache_flush();
|
||||
rt_hw_cpu_dcache_disable();
|
||||
rt_hw_cpu_icache_disable();
|
||||
rt_cpu_mmu_disable();
|
||||
|
||||
/*rt_hw_cpu_dump_page_table(MMUTable);*/
|
||||
rt_hw_set_domain_register(0x55555555);
|
||||
|
||||
rt_cpu_tlb_set(MMUTable);
|
||||
|
||||
rt_cpu_mmu_enable();
|
||||
|
||||
rt_hw_cpu_icache_enable();
|
||||
rt_hw_cpu_dcache_enable();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-03-25 quanzhao the first version
|
||||
*/
|
||||
#ifndef __MMU_H_
|
||||
#define __MMU_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define DESC_SEC (0x2)
|
||||
#define MEMWBWA ((1<<12)|(3<<2)) /* write back, write allocate */
|
||||
#define MEMWB (3<<2) /* write back, no write allocate */
|
||||
#define MEMWT (2<<2) /* write through, no write allocate */
|
||||
#define SHAREDEVICE (1<<2) /* shared device */
|
||||
#define STRONGORDER (0<<2) /* strong ordered */
|
||||
#define XN (1<<4) /* eXecute Never */
|
||||
#define AP_RW (3<<10) /* supervisor=RW, user=RW */
|
||||
#define AP_RO (2<<10) /* supervisor=RW, user=RO */
|
||||
#define SHARED (1<<16) /* shareable */
|
||||
|
||||
#define DOMAIN_FAULT (0x0)
|
||||
#define DOMAIN_CHK (0x1)
|
||||
#define DOMAIN_NOTCHK (0x3)
|
||||
#define DOMAIN0 (0x0<<5)
|
||||
#define DOMAIN1 (0x1<<5)
|
||||
|
||||
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
|
||||
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
|
||||
|
||||
/* device mapping type */
|
||||
#define DEVICE_MEM (SHARED|AP_RW|DOMAIN0|SHAREDEVICE|DESC_SEC|XN)
|
||||
/* normal memory mapping type */
|
||||
#define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC)
|
||||
|
||||
struct mem_desc
|
||||
{
|
||||
rt_uint32_t vaddr_start;
|
||||
rt_uint32_t vaddr_end;
|
||||
rt_uint32_t paddr_start;
|
||||
rt_uint32_t attr;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-09-23 Bernard the first version
|
||||
* 2011-10-05 Bernard add thumb mode
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <board.h>
|
||||
#include <armv7.h>
|
||||
|
||||
/**
|
||||
* @addtogroup AM33xx
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
|
||||
rt_uint8_t *stack_addr, void *texit)
|
||||
{
|
||||
rt_uint32_t *stk;
|
||||
|
||||
stack_addr += sizeof(rt_uint32_t);
|
||||
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
|
||||
stk = (rt_uint32_t *)stack_addr;
|
||||
*(--stk) = (rt_uint32_t)tentry; /* entry point */
|
||||
*(--stk) = (rt_uint32_t)texit; /* lr */
|
||||
*(--stk) = 0xdeadbeef; /* r12 */
|
||||
*(--stk) = 0xdeadbeef; /* r11 */
|
||||
*(--stk) = 0xdeadbeef; /* r10 */
|
||||
*(--stk) = 0xdeadbeef; /* r9 */
|
||||
*(--stk) = 0xdeadbeef; /* r8 */
|
||||
*(--stk) = 0xdeadbeef; /* r7 */
|
||||
*(--stk) = 0xdeadbeef; /* r6 */
|
||||
*(--stk) = 0xdeadbeef; /* r5 */
|
||||
*(--stk) = 0xdeadbeef; /* r4 */
|
||||
*(--stk) = 0xdeadbeef; /* r3 */
|
||||
*(--stk) = 0xdeadbeef; /* r2 */
|
||||
*(--stk) = 0xdeadbeef; /* r1 */
|
||||
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
|
||||
/* cpsr */
|
||||
if ((rt_uint32_t)tentry & 0x01)
|
||||
*(--stk) = SVCMODE | 0x20; /* thumb mode */
|
||||
else
|
||||
*(--stk) = SVCMODE; /* arm mode */
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
*(--stk) = 0; /* user lr */
|
||||
*(--stk) = 0; /* user sp*/
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
*(--stk) = 0; /* not use fpu*/
|
||||
#endif
|
||||
|
||||
/* return task's current stack address */
|
||||
return (rt_uint8_t *)stk;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
* 2018-11-22 Jesven in the interrupt context, use rt_scheduler_do_irq_switch checks
|
||||
* and switches to a new thread
|
||||
*/
|
||||
|
||||
#include "rtconfig.h"
|
||||
.equ Mode_USR, 0x10
|
||||
.equ Mode_FIQ, 0x11
|
||||
.equ Mode_IRQ, 0x12
|
||||
.equ Mode_SVC, 0x13
|
||||
.equ Mode_ABT, 0x17
|
||||
.equ Mode_UND, 0x1B
|
||||
.equ Mode_SYS, 0x1F
|
||||
|
||||
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
|
||||
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
|
||||
|
||||
.equ UND_Stack_Size, 0x00000400
|
||||
.equ SVC_Stack_Size, 0x00000400
|
||||
.equ ABT_Stack_Size, 0x00000400
|
||||
.equ RT_FIQ_STACK_PGSZ, 0x00000000
|
||||
.equ RT_IRQ_STACK_PGSZ, 0x00000800
|
||||
.equ USR_Stack_Size, 0x00000400
|
||||
|
||||
.equ SUB_UND_Stack_Size, 0x00000400
|
||||
.equ SUB_SVC_Stack_Size, 0x00000400
|
||||
.equ SUB_ABT_Stack_Size, 0x00000400
|
||||
.equ SUB_RT_FIQ_STACK_PGSZ, 0x00000000
|
||||
.equ SUB_RT_IRQ_STACK_PGSZ, 0x00000400
|
||||
.equ SUB_USR_Stack_Size, 0x00000400
|
||||
|
||||
#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
|
||||
RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ)
|
||||
|
||||
#define SUB_ISR_Stack_Size (SUB_UND_Stack_Size + SUB_SVC_Stack_Size + SUB_ABT_Stack_Size + \
|
||||
SUB_RT_FIQ_STACK_PGSZ + SUB_RT_IRQ_STACK_PGSZ)
|
||||
|
||||
.section .bss.share.isr
|
||||
/* stack */
|
||||
.globl stack_start
|
||||
.globl stack_top
|
||||
|
||||
.align 3
|
||||
stack_start:
|
||||
.rept ISR_Stack_Size
|
||||
.byte 0
|
||||
.endr
|
||||
stack_top:
|
||||
|
||||
.text
|
||||
/* reset entry */
|
||||
.globl _reset
|
||||
_reset:
|
||||
#ifdef ARCH_ARMV8
|
||||
/* Check for HYP mode */
|
||||
mrs r0, cpsr_all
|
||||
and r0, r0, #0x1F
|
||||
mov r8, #0x1A
|
||||
cmp r0, r8
|
||||
beq overHyped
|
||||
b continue
|
||||
|
||||
overHyped: /* Get out of HYP mode */
|
||||
adr r1, continue
|
||||
msr ELR_hyp, r1
|
||||
mrs r1, cpsr_all
|
||||
and r1, r1, #0x1f ;@ CPSR_MODE_MASK
|
||||
orr r1, r1, #0x13 ;@ CPSR_MODE_SUPERVISOR
|
||||
msr SPSR_hyp, r1
|
||||
eret
|
||||
|
||||
continue:
|
||||
#endif
|
||||
/* set the cpu to SVC32 mode and disable interrupt */
|
||||
cps #Mode_SVC
|
||||
|
||||
#ifdef RT_USING_FPU
|
||||
mov r4, #0xfffffff
|
||||
mcr p15, 0, r4, c1, c0, 2
|
||||
#endif
|
||||
|
||||
/* disable the data alignment check */
|
||||
mrc p15, 0, r1, c1, c0, 0
|
||||
bic r1, #(1<<0) /* Disable MMU */
|
||||
bic r1, #(1<<1) /* Disable Alignment fault checking */
|
||||
bic r1, #(1<<2) /* Disable data cache */
|
||||
bic r1, #(1<<11) /* Disable program flow prediction */
|
||||
bic r1, #(1<<12) /* Disable instruction cache */
|
||||
bic r1, #(3<<19) /* bit[20:19] must be zero */
|
||||
mcr p15, 0, r1, c1, c0, 0
|
||||
|
||||
@ get cpu id, and subtract the offset from the stacks base address
|
||||
bl rt_hw_cpu_id
|
||||
mov r5, r0
|
||||
|
||||
cmp r5, #0 @ cpu id == 0
|
||||
beq normal_setup
|
||||
|
||||
@ cpu id > 0, stop or wait
|
||||
#ifdef RT_SMP_AUTO_BOOT
|
||||
ldr r0, =secondary_cpu_entry
|
||||
mov r1, #0
|
||||
str r1, [r0] /* clean secondary_cpu_entry */
|
||||
#endif /* RT_SMP_AUTO_BOOT */
|
||||
|
||||
secondary_loop:
|
||||
@ cpu core 1 goes into sleep until core 0 wakeup it
|
||||
wfe
|
||||
#ifdef RT_SMP_AUTO_BOOT
|
||||
ldr r1, =secondary_cpu_entry
|
||||
ldr r0, [r1]
|
||||
cmp r0, #0
|
||||
blxne r0 /* if(secondary_cpu_entry) secondary_cpu_entry(); */
|
||||
#endif /* RT_SMP_AUTO_BOOT */
|
||||
b secondary_loop
|
||||
|
||||
normal_setup:
|
||||
/* setup stack */
|
||||
bl stack_setup
|
||||
|
||||
/* clear .bss */
|
||||
mov r0,#0 /* get a zero */
|
||||
ldr r1,=__bss_start /* bss start */
|
||||
ldr r2,=__bss_end /* bss end */
|
||||
|
||||
bss_loop:
|
||||
cmp r1,r2 /* check if data to clear */
|
||||
strlo r0,[r1],#4 /* clear 4 bytes */
|
||||
blo bss_loop /* loop until done */
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
mrc p15, 0, r1, c1, c0, 1
|
||||
mov r0, #(1<<6)
|
||||
orr r1, r0
|
||||
mcr p15, 0, r1, c1, c0, 1 //enable smp
|
||||
#endif
|
||||
|
||||
/* enable branch prediction */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
orr r0, r0, #(1<<11)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
/* initialize the mmu table and enable mmu */
|
||||
ldr r0, =platform_mem_desc
|
||||
ldr r1, =platform_mem_desc_size
|
||||
ldr r1, [r1]
|
||||
bl rt_hw_init_mmu_table
|
||||
bl rt_hw_mmu_init
|
||||
|
||||
/* call C++ constructors of global objects */
|
||||
ldr r0, =__ctors_start__
|
||||
ldr r1, =__ctors_end__
|
||||
|
||||
ctor_loop:
|
||||
cmp r0, r1
|
||||
beq ctor_end
|
||||
ldr r2, [r0], #4
|
||||
stmfd sp!, {r0-r1}
|
||||
mov lr, pc
|
||||
bx r2
|
||||
ldmfd sp!, {r0-r1}
|
||||
b ctor_loop
|
||||
ctor_end:
|
||||
|
||||
/* start RT-Thread Kernel */
|
||||
ldr pc, _rtthread_startup
|
||||
_rtthread_startup:
|
||||
.word rtthread_startup
|
||||
|
||||
stack_setup:
|
||||
ldr r0, =stack_top
|
||||
|
||||
@ Set the startup stack for svc
|
||||
mov sp, r0
|
||||
sub r0, r0, #SVC_Stack_Size
|
||||
|
||||
@ Enter Undefined Instruction Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_UND|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #UND_Stack_Size
|
||||
|
||||
@ Enter Abort Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_ABT|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #ABT_Stack_Size
|
||||
|
||||
@ Enter FIQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #RT_FIQ_STACK_PGSZ
|
||||
|
||||
@ Enter IRQ Mode and set its Stack Pointer
|
||||
msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
|
||||
mov sp, r0
|
||||
sub r0, r0, #RT_IRQ_STACK_PGSZ
|
||||
|
||||
/* come back to SVC mode */
|
||||
msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
|
||||
bx lr
|
||||
|
||||
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
|
||||
.section .text.isr, "ax"
|
||||
.align 5
|
||||
.globl vector_fiq
|
||||
vector_fiq:
|
||||
stmfd sp!,{r0-r7,lr}
|
||||
bl rt_hw_trap_fiq
|
||||
ldmfd sp!,{r0-r7,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
.globl rt_interrupt_enter
|
||||
.globl rt_interrupt_leave
|
||||
.globl rt_thread_switch_interrupt_flag
|
||||
.globl rt_interrupt_from_thread
|
||||
.globl rt_interrupt_to_thread
|
||||
|
||||
.globl rt_current_thread
|
||||
.globl vmm_thread
|
||||
.globl vmm_virq_check
|
||||
|
||||
.align 5
|
||||
.globl vector_irq
|
||||
vector_irq:
|
||||
#ifdef RT_USING_SMP
|
||||
clrex
|
||||
|
||||
stmfd sp!, {r0, r1}
|
||||
cps #Mode_SVC
|
||||
mov r0, sp /* svc_sp */
|
||||
mov r1, lr /* svc_lr */
|
||||
|
||||
cps #Mode_IRQ
|
||||
sub lr, #4
|
||||
stmfd r0!, {r1, lr} /* svc_lr, svc_pc */
|
||||
stmfd r0!, {r2 - r12}
|
||||
ldmfd sp!, {r1, r2} /* original r0, r1 */
|
||||
stmfd r0!, {r1 - r2}
|
||||
mrs r1, spsr /* original mode */
|
||||
stmfd r0!, {r1}
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */
|
||||
sub r0, #8
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
vmrs r6, fpexc
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
vstmdb r0!, {d0-d15}
|
||||
vstmdb r0!, {d16-d31}
|
||||
vmrs r5, fpscr
|
||||
stmfd r0!, {r5}
|
||||
1:
|
||||
stmfd r0!, {r6}
|
||||
#endif
|
||||
|
||||
/* now irq stack is clean */
|
||||
/* r0 is task svc_sp */
|
||||
/* backup r0 -> r8 */
|
||||
mov r8, r0
|
||||
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
cps #Mode_SVC
|
||||
mov sp, r8
|
||||
mov r0, r8
|
||||
bl rt_scheduler_do_irq_switch
|
||||
|
||||
b rt_hw_context_switch_exit
|
||||
|
||||
#else
|
||||
stmfd sp!, {r0-r12,lr}
|
||||
|
||||
bl rt_interrupt_enter
|
||||
bl rt_hw_trap_irq
|
||||
bl rt_interrupt_leave
|
||||
|
||||
@ if rt_thread_switch_interrupt_flag set, jump to
|
||||
@ rt_hw_context_switch_interrupt_do and don't return
|
||||
ldr r0, =rt_thread_switch_interrupt_flag
|
||||
ldr r1, [r0]
|
||||
cmp r1, #1
|
||||
beq rt_hw_context_switch_interrupt_do
|
||||
|
||||
ldmfd sp!, {r0-r12,lr}
|
||||
subs pc, lr, #4
|
||||
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
mov r1, #0 @ clear flag
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, sp @ r1 point to {r0-r3} in stack
|
||||
add sp, sp, #4*4
|
||||
ldmfd sp!, {r4-r12,lr}@ reload saved registers
|
||||
mrs r0, spsr @ get cpsr of interrupt thread
|
||||
sub r2, lr, #4 @ save old task's pc to r2
|
||||
|
||||
@ Switch to SVC mode with no interrupt. If the usr mode guest is
|
||||
@ interrupted, this will just switch to the stack of kernel space.
|
||||
@ save the registers in kernel space won't trigger data abort.
|
||||
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
|
||||
|
||||
stmfd sp!, {r2} @ push old task's pc
|
||||
stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4
|
||||
ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread
|
||||
stmfd sp!, {r1-r4} @ push old task's r0-r3
|
||||
stmfd sp!, {r0} @ push old task's cpsr
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
stmfd sp, {r13, r14}^ @push usr_sp, usr_lr
|
||||
sub sp, #8
|
||||
#endif
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
vmrs r6, fpexc
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
vstmdb sp!, {d0-d15}
|
||||
vstmdb sp!, {d16-d31}
|
||||
vmrs r5, fpscr
|
||||
stmfd sp!, {r5}
|
||||
1:
|
||||
stmfd sp!, {r6}
|
||||
#endif
|
||||
|
||||
ldr r4, =rt_interrupt_from_thread
|
||||
ldr r5, [r4]
|
||||
str sp, [r5] @ store sp in preempted tasks's TCB
|
||||
|
||||
ldr r6, =rt_interrupt_to_thread
|
||||
ldr r6, [r6]
|
||||
ldr sp, [r6] @ get new task's stack pointer
|
||||
|
||||
bl rt_interrupt_hook
|
||||
|
||||
#ifdef RT_USING_FPU
|
||||
/* fpu context */
|
||||
ldmfd sp!, {r6}
|
||||
vmsr fpexc, r6
|
||||
tst r6, #(1<<30)
|
||||
beq 1f
|
||||
ldmfd sp!, {r5}
|
||||
vmsr fpscr, r5
|
||||
vldmia sp!, {d16-d31}
|
||||
vldmia sp!, {d0-d15}
|
||||
1:
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
ldmfd sp, {r13, r14}^ @pop usr_sp, usr_lr
|
||||
add sp, #8
|
||||
#endif
|
||||
|
||||
ldmfd sp!, {r4} @ pop new task's cpsr to spsr
|
||||
msr spsr_cxsf, r4
|
||||
|
||||
ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
|
||||
|
||||
#endif
|
||||
|
||||
.macro push_svc_reg
|
||||
sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */
|
||||
stmia sp, {r0 - r12} @/* Calling r0-r12 */
|
||||
mov r0, sp
|
||||
mrs r6, spsr @/* Save CPSR */
|
||||
str lr, [r0, #15*4] @/* Push PC */
|
||||
str r6, [r0, #16*4] @/* Push CPSR */
|
||||
mrs r5, cpsr @/* Save CPSR */
|
||||
|
||||
and r4, r6, #0x1F
|
||||
cmp r4, #Mode_USR
|
||||
moveq r6, #Mode_SYS
|
||||
|
||||
orr r6, r6, #0x80 @/* Switch to previous mode, then save SP & PC */
|
||||
msr cpsr_c, r6
|
||||
str sp, [r0, #13*4] @/* Save calling SP */
|
||||
str lr, [r0, #14*4] @/* Save calling PC */
|
||||
|
||||
msr cpsr_c, r5 @/* Switch back to current mode */
|
||||
.endm
|
||||
|
||||
.align 5
|
||||
.weak vector_swi
|
||||
vector_swi:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_swi
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_undef
|
||||
vector_undef:
|
||||
push_svc_reg
|
||||
cps #Mode_UND
|
||||
bl rt_hw_trap_undef
|
||||
#ifdef RT_USING_FPU
|
||||
ldr lr, [sp, #15*4]
|
||||
ldmia sp, {r0 - r12}
|
||||
add sp, sp, #17 * 4
|
||||
movs pc, lr
|
||||
#endif
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_pabt
|
||||
vector_pabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_pabt
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_dabt
|
||||
vector_dabt:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_dabt
|
||||
b .
|
||||
|
||||
.align 5
|
||||
.globl vector_resv
|
||||
vector_resv:
|
||||
push_svc_reg
|
||||
bl rt_hw_trap_resv
|
||||
b .
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
.global secondary_cpu_start
|
||||
secondary_cpu_start:
|
||||
|
||||
#ifdef RT_USING_FPU
|
||||
mov r4, #0xfffffff
|
||||
mcr p15, 0, r4, c1, c0, 2
|
||||
#endif
|
||||
|
||||
mrc p15, 0, r1, c1, c0, 1
|
||||
mov r0, #(1<<6)
|
||||
orr r1, r0
|
||||
mcr p15, 0, r1, c1, c0, 1 //enable smp
|
||||
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, #(1<<13)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
/* enable branch prediction */
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
orr r0, r0, #(1<<11)
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
@ get cpu id, and subtract the offset from the stacks base address
|
||||
bl rt_hw_cpu_id
|
||||
sub r5, r0, #1
|
||||
|
||||
ldr r0, =SUB_ISR_Stack_Size
|
||||
mul r0, r0, r5 @r0 = SUB_ISR_Stack_Size * (cpuid - 1)
|
||||
ldr r1, =sub_stack_top
|
||||
sub r0, r1, r0 @r0 = sub_stack_top - (SUB_ISR_Stack_Size * (cpuid - 1))
|
||||
|
||||
cps #Mode_SVC
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_SVC_Stack_Size
|
||||
|
||||
cps #Mode_UND
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_UND_Stack_Size
|
||||
|
||||
cps #Mode_ABT
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_ABT_Stack_Size
|
||||
|
||||
cps #Mode_FIQ
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_RT_FIQ_STACK_PGSZ
|
||||
|
||||
cps #Mode_IRQ
|
||||
mov sp, r0
|
||||
sub r0, r0, #SUB_RT_IRQ_STACK_PGSZ
|
||||
|
||||
cps #Mode_SVC
|
||||
|
||||
/* initialize the mmu table and enable mmu */
|
||||
bl rt_hw_mmu_init
|
||||
|
||||
b secondary_cpu_c_start
|
||||
|
||||
.bss
|
||||
.align 2 //align to 2~2=4
|
||||
|
||||
.global sub_stack_top /* used for backtrace to calculate stack top of irq mode */
|
||||
|
||||
sub_stack_start:
|
||||
.space (SUB_ISR_Stack_Size * (RT_CPUS_NR-1))
|
||||
sub_stack_top:
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-20 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
|
||||
#include "armv7.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* this function will show registers of CPU
|
||||
*
|
||||
* @param regs the registers point
|
||||
*/
|
||||
void rt_hw_show_register(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
rt_kprintf("Execption:\n");
|
||||
rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10);
|
||||
rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip);
|
||||
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc);
|
||||
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
|
||||
}
|
||||
|
||||
void (*rt_trap_hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type);
|
||||
|
||||
/**
|
||||
* This function will set a hook function to trap handler.
|
||||
*
|
||||
* @param hook the hook function
|
||||
*/
|
||||
void rt_hw_trap_set_hook(void (*hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type))
|
||||
{
|
||||
rt_trap_hook = hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* When comes across an instruction which it cannot handle,
|
||||
* it takes the undefined instruction trap.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_undef(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
#ifdef RT_USING_FPU
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t addr;
|
||||
|
||||
if (regs->cpsr & (1 << 5))
|
||||
{
|
||||
/* thumb mode */
|
||||
addr = regs->pc - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = regs->pc - 4;
|
||||
}
|
||||
asm volatile ("vmrs %0, fpexc" : "=r"(val)::"memory");
|
||||
|
||||
if (!(val & 0x40000000))
|
||||
{
|
||||
/* float ins */
|
||||
val = (1U << 30);
|
||||
|
||||
asm volatile ("vmsr fpexc, %0"::"r"(val):"memory");
|
||||
regs->pc = addr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("undefined instruction:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "undefined instruction", UND_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The software interrupt instruction (SWI) is used for entering
|
||||
* Supervisor mode, usually to request a particular supervisor
|
||||
* function.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_swi(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("software interrupt:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "software instruction", SWI_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during an instruction prefetch.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("prefetch abort:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "prefetch abort", PABT_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An abort indicates that the current memory access cannot be completed,
|
||||
* which occurs during a data access.
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("data abort:");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "data abort", DABT_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normally, system will never reach here
|
||||
*
|
||||
* @param regs system registers
|
||||
*
|
||||
* @note never invoke this function in application
|
||||
*/
|
||||
void rt_hw_trap_resv(struct rt_hw_exp_stack *regs)
|
||||
{
|
||||
if (rt_trap_hook == RT_NULL)
|
||||
{
|
||||
rt_kprintf("reserved trap:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "reserved trap", RESV_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_trap_irq(void)
|
||||
{
|
||||
void *param;
|
||||
int int_ack;
|
||||
int ir;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
int_ack = rt_hw_interrupt_get_irq();
|
||||
|
||||
ir = int_ack & GIC_ACK_INTID_MASK;
|
||||
if (ir == 1023)
|
||||
{
|
||||
/* Spurious interrupt */
|
||||
return;
|
||||
}
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[ir].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
/* Interrupt for myself. */
|
||||
param = isr_table[ir].param;
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(ir, param);
|
||||
}
|
||||
|
||||
/* end of interrupt */
|
||||
rt_hw_interrupt_ack(int_ack);
|
||||
}
|
||||
|
||||
void rt_hw_trap_fiq(void)
|
||||
{
|
||||
void *param;
|
||||
int ir;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
ir = rt_hw_interrupt_get_irq();
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[ir].handler;
|
||||
param = isr_table[ir].param;
|
||||
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(ir, param);
|
||||
|
||||
/* end of interrupt */
|
||||
rt_hw_interrupt_ack(ir);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-07-05 Bernard the first version
|
||||
*/
|
||||
|
||||
.section .vectors, "ax"
|
||||
.code 32
|
||||
|
||||
.globl system_vectors
|
||||
system_vectors:
|
||||
ldr pc, _vector_reset
|
||||
ldr pc, _vector_undef
|
||||
ldr pc, _vector_swi
|
||||
ldr pc, _vector_pabt
|
||||
ldr pc, _vector_dabt
|
||||
ldr pc, _vector_resv
|
||||
ldr pc, _vector_irq
|
||||
ldr pc, _vector_fiq
|
||||
|
||||
.globl _reset
|
||||
.globl vector_undef
|
||||
.globl vector_swi
|
||||
.globl vector_pabt
|
||||
.globl vector_dabt
|
||||
.globl vector_resv
|
||||
.globl vector_irq
|
||||
.globl vector_fiq
|
||||
|
||||
_vector_reset:
|
||||
.word _reset
|
||||
_vector_undef:
|
||||
.word vector_undef
|
||||
_vector_swi:
|
||||
.word vector_swi
|
||||
_vector_pabt:
|
||||
.word vector_pabt
|
||||
_vector_dabt:
|
||||
.word vector_dabt
|
||||
_vector_resv:
|
||||
.word vector_resv
|
||||
_vector_irq:
|
||||
.word vector_irq
|
||||
_vector_fiq:
|
||||
.word vector_fiq
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2013-02-20 aozima port to gcc.
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-11-04 bright fixed hardfault bug for gcc.
|
||||
*/
|
||||
|
||||
.cpu cortex-m0
|
||||
.fpu softvfp
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
|
||||
.equ NVIC_SHPR3, 0xE000ED20 /* system priority register (3) */
|
||||
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* R0 --> from
|
||||
* R1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOVS R3, #1
|
||||
STR R3, [R2]
|
||||
|
||||
LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR R0, [R2]
|
||||
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR R1, [R2]
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
BX LR
|
||||
|
||||
/* R0 --> switch from thread stack
|
||||
* R1 --> switch to thread stack
|
||||
* psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS R2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ pendsv_exit /* pendsv aLReady handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOVS R1, #0
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =rt_interrupt_from_thread
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS R1, PSP /* get from thread stack pointer */
|
||||
|
||||
SUBS R1, R1, #0x20 /* space for {R4 - R7} and {R8 - R11} */
|
||||
LDR R0, [R0]
|
||||
STR R1, [R0] /* update from thread stack pointer */
|
||||
|
||||
STMIA R1!, {R4 - R7} /* push thread {R4 - R7} register to thread stack */
|
||||
|
||||
MOV R4, R8 /* mov thread {R8 - R11} to {R4 - R7} */
|
||||
MOV R5, R9
|
||||
MOV R6, R10
|
||||
MOV R7, R11
|
||||
STMIA R1!, {R4 - R7} /* push thread {R8 - R11} high register to thread stack */
|
||||
switch_to_thread:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
LDR R1, [R1]
|
||||
LDR R1, [R1] /* load thread stack pointer */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R4 - R7} register from thread stack */
|
||||
PUSH {R4 - R7} /* push {R4 - R7} to MSP for copy {R8 - R11} */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */
|
||||
MOV R8, R4 /* mov {R4 - R7} to {R8 - R11} */
|
||||
MOV R9, R5
|
||||
MOV R10, R6
|
||||
MOV R11, R7
|
||||
|
||||
POP {R4 - R7} /* pop {R4 - R7} from MSP */
|
||||
|
||||
MSR PSP, R1 /* update stack pointer */
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, R2
|
||||
|
||||
MOVS R0, #0x04
|
||||
RSBS R0, R0, #0x00
|
||||
BX R0
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* R0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
STR R0, [R1]
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR R1, =rt_interrupt_from_thread
|
||||
MOVS R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR R1, =rt_thread_switch_interrupt_flag
|
||||
MOVS R0, #1
|
||||
STR R0, [R1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR R0, =NVIC_SHPR3
|
||||
LDR R1, =NVIC_PENDSV_PRI
|
||||
LDR R2, [R0,#0x00] /* read */
|
||||
ORRS R1, R1, R2 /* modify */
|
||||
STR R1, [R0] /* write-back */
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
NOP
|
||||
/* restore MSP */
|
||||
LDR R0, =SCB_VTOR
|
||||
LDR R0, [R0]
|
||||
LDR R0, [R0]
|
||||
NOP
|
||||
MSR MSP, R0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE I
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX LR
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS R0, PSP /* get fault thread stack pointer */
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {PC}
|
||||
|
||||
|
||||
/*
|
||||
* rt_uint32_t rt_hw_interrupt_check(void);
|
||||
* R0 --> state
|
||||
*/
|
||||
.global rt_hw_interrupt_check
|
||||
.type rt_hw_interrupt_check, %function
|
||||
rt_hw_interrupt_check:
|
||||
MRS R0, IPSR
|
||||
BX LR
|
||||
@@ -0,0 +1,206 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M0
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x04
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
NOP
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
|
||||
END
|
||||
@@ -0,0 +1,215 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M0
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x01
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x04
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
|
||||
HardFault_Handler PROC
|
||||
EXPORT HardFault_Handler
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-05-31 aozima Merge all of the C source code into cpuport.c
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
/* r4 ~ r7 low register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
|
||||
/* r8 ~ r11 high register */
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
/* flag in interrupt handling */
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
extern rt_thread_t rt_current_thread;
|
||||
/**
|
||||
* fault exception handling
|
||||
*/
|
||||
void rt_hw_hard_fault_exception(struct exception_stack_frame *contex)
|
||||
{
|
||||
rt_kprintf("psr: 0x%08x\n", contex->psr);
|
||||
rt_kprintf(" pc: 0x%08x\n", contex->pc);
|
||||
rt_kprintf(" lr: 0x%08x\n", contex->lr);
|
||||
rt_kprintf("r12: 0x%08x\n", contex->r12);
|
||||
rt_kprintf("r03: 0x%08x\n", contex->r3);
|
||||
rt_kprintf("r02: 0x%08x\n", contex->r2);
|
||||
rt_kprintf("r01: 0x%08x\n", contex->r1);
|
||||
rt_kprintf("r00: 0x%08x\n", contex->r0);
|
||||
|
||||
rt_kprintf("hard fault on thread: %s\n", rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;//((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |SCB_AIRCR_SYSRESETREQ_Msk);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2013-02-20 aozima port to gcc.
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-11-04 bright fixed hardfault bug for gcc.
|
||||
* 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
*/
|
||||
|
||||
.cpu cortex-m23
|
||||
.fpu softvfp
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
|
||||
.equ NVIC_SHPR3, 0xE000ED20 /* system priority register (3) */
|
||||
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* R0 --> from
|
||||
* R1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOVS R3, #1
|
||||
STR R3, [R2]
|
||||
|
||||
LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR R0, [R2]
|
||||
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR R1, [R2]
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
BX LR
|
||||
|
||||
/* R0 --> switch from thread stack
|
||||
* R1 --> switch to thread stack
|
||||
* psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS R2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ pendsv_exit /* pendsv aLReady handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOVS R1, #0
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =rt_interrupt_from_thread
|
||||
LDR R1, [R0]
|
||||
CMP R1, #0x00
|
||||
BEQ switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS R1, PSP /* get from thread stack pointer */
|
||||
|
||||
SUBS R1, R1, #0x20 /* space for {R4 - R7} and {R8 - R11} */
|
||||
LDR R0, [R0]
|
||||
STR R1, [R0] /* update from thread stack pointer */
|
||||
|
||||
STMIA R1!, {R4 - R7} /* push thread {R4 - R7} register to thread stack */
|
||||
|
||||
MOV R4, R8 /* mov thread {R8 - R11} to {R4 - R7} */
|
||||
MOV R5, R9
|
||||
MOV R6, R10
|
||||
MOV R7, R11
|
||||
STMIA R1!, {R4 - R7} /* push thread {R8 - R11} high register to thread stack */
|
||||
switch_to_thread:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
LDR R1, [R1]
|
||||
LDR R1, [R1] /* load thread stack pointer */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R4 - R7} register from thread stack */
|
||||
PUSH {R4 - R7} /* push {R4 - R7} to MSP for copy {R8 - R11} */
|
||||
|
||||
LDMIA R1!, {R4 - R7} /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */
|
||||
MOV R8, R4 /* mov {R4 - R7} to {R8 - R11} */
|
||||
MOV R9, R5
|
||||
MOV R10, R6
|
||||
MOV R11, R7
|
||||
|
||||
POP {R4 - R7} /* pop {R4 - R7} from MSP */
|
||||
|
||||
MSR PSP, R1 /* update stack pointer */
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, R2
|
||||
|
||||
MOVS R0, #0x03
|
||||
RSBS R0, R0, #0x00
|
||||
BX R0
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* R0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
STR R0, [R1]
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR R1, =rt_interrupt_from_thread
|
||||
MOVS R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR R1, =rt_thread_switch_interrupt_flag
|
||||
MOVS R0, #1
|
||||
STR R0, [R1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR R0, =NVIC_SHPR3
|
||||
LDR R1, =NVIC_PENDSV_PRI
|
||||
LDR R2, [R0,#0x00] /* read */
|
||||
ORRS R1, R1, R2 /* modify */
|
||||
STR R1, [R0] /* write-back */
|
||||
|
||||
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =NVIC_PENDSVSET
|
||||
STR R1, [R0]
|
||||
NOP
|
||||
/* restore MSP */
|
||||
LDR R0, =SCB_VTOR
|
||||
LDR R0, [R0]
|
||||
LDR R0, [R0]
|
||||
NOP
|
||||
MSR MSP, R0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE I
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX LR
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS R0, PSP /* get fault thread stack pointer */
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {PC}
|
||||
|
||||
|
||||
/*
|
||||
* rt_uint32_t rt_hw_interrupt_check(void);
|
||||
* R0 --> state
|
||||
*/
|
||||
.global rt_hw_interrupt_check
|
||||
.type rt_hw_interrupt_check, %function
|
||||
rt_hw_interrupt_check:
|
||||
MRS R0, IPSR
|
||||
BX LR
|
||||
@@ -0,0 +1,207 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M23
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x03
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
NOP
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
|
||||
END
|
||||
@@ -0,0 +1,216 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2010-01-25 Bernard first version
|
||||
; * 2012-06-01 aozima set pendsv priority to 0xFF.
|
||||
; * 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M23
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOVS r3, #0x01
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOVS r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CMP r1, #0x00
|
||||
BEQ switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
|
||||
SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11}
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack
|
||||
|
||||
MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7}
|
||||
MOV r5, r9
|
||||
MOV r6, r10
|
||||
MOV r7, r11
|
||||
STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack
|
||||
PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11}
|
||||
|
||||
LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7}
|
||||
MOV r8, r4 ; mov {r4 - r7} to {r8 - r11}
|
||||
MOV r9, r5
|
||||
MOV r10, r6
|
||||
MOV r11, r7
|
||||
|
||||
POP {r4 - r7} ; pop {r4 - r7} from MSP
|
||||
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
MOVS r0, #0x03
|
||||
RSBS r0, r0, #0x00
|
||||
BX r0
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOVS r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOVS r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SHPR3
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR r2, [r0,#0x00] ; read
|
||||
ORRS r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE I
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
|
||||
HardFault_Handler PROC
|
||||
EXPORT HardFault_Handler
|
||||
|
||||
; get current context
|
||||
MRS r0, psp ; get fault thread stack pointer
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {pc}
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-01-25 Bernard first version
|
||||
* 2012-05-31 aozima Merge all of the C source code into cpuport.c
|
||||
* 2012-08-17 aozima fixed bug: store r8 - r11.
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
* 2019-03-31 xuzhuoyi port to Cortex-M23.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
/* r4 ~ r7 low register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
|
||||
/* r8 ~ r11 high register */
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
/* flag in interrupt handling */
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
extern rt_thread_t rt_current_thread;
|
||||
/**
|
||||
* fault exception handling
|
||||
*/
|
||||
void rt_hw_hard_fault_exception(struct exception_stack_frame *contex)
|
||||
{
|
||||
rt_kprintf("psr: 0x%08x\n", contex->psr);
|
||||
rt_kprintf(" pc: 0x%08x\n", contex->pc);
|
||||
rt_kprintf(" lr: 0x%08x\n", contex->lr);
|
||||
rt_kprintf("r12: 0x%08x\n", contex->r12);
|
||||
rt_kprintf("r03: 0x%08x\n", contex->r3);
|
||||
rt_kprintf("r02: 0x%08x\n", contex->r2);
|
||||
rt_kprintf("r01: 0x%08x\n", contex->r1);
|
||||
rt_kprintf("r00: 0x%08x\n", contex->r0);
|
||||
|
||||
rt_kprintf("hard fault on thread: %s\n", rt_current_thread->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED00) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;//((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |SCB_AIRCR_SYSRESETREQ_Msk);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if rtconfig.PLATFORM == 'armcc' or rtconfig.PLATFORM == 'armclang':
|
||||
src += Glob('*_rvds.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'gcc':
|
||||
src += Glob('*_init.S')
|
||||
src += Glob('*_gcc.S')
|
||||
|
||||
if rtconfig.PLATFORM == 'iar':
|
||||
src += Glob('*_iar.S')
|
||||
|
||||
group = DefineGroup('CPU', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-10-11 Bernard First version
|
||||
* 2010-12-29 onelife Modify for EFM32
|
||||
* 2011-06-17 onelife Merge all of the assembly source code into context_gcc.S
|
||||
* 2011-07-12 onelife Add interrupt context check function
|
||||
* 2013-06-18 aozima add restore MSP feature.
|
||||
* 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
*/
|
||||
|
||||
.cpu cortex-m3
|
||||
.fpu softvfp
|
||||
.syntax unified
|
||||
.thumb
|
||||
.text
|
||||
|
||||
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
|
||||
.equ ICSR, 0xE000ED04 /* interrupt control state register */
|
||||
.equ PENDSVSET_BIT, 0x10000000 /* value to trigger PendSV exception */
|
||||
|
||||
.equ SHPR3, 0xE000ED20 /* system priority register (3) */
|
||||
.equ PENDSV_PRI_LOWEST, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
|
||||
|
||||
/*
|
||||
* rt_base_t rt_hw_interrupt_disable();
|
||||
*/
|
||||
.global rt_hw_interrupt_disable
|
||||
.type rt_hw_interrupt_disable, %function
|
||||
rt_hw_interrupt_disable:
|
||||
MRS R0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_interrupt_enable(rt_base_t level);
|
||||
*/
|
||||
.global rt_hw_interrupt_enable
|
||||
.type rt_hw_interrupt_enable, %function
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, R0
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
* R0 --> from
|
||||
* R1 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_interrupt
|
||||
.type rt_hw_context_switch_interrupt, %function
|
||||
.global rt_hw_context_switch
|
||||
.type rt_hw_context_switch, %function
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
/* set rt_thread_switch_interrupt_flag to 1 */
|
||||
LDR R2, =rt_thread_switch_interrupt_flag
|
||||
LDR R3, [R2]
|
||||
CMP R3, #1
|
||||
BEQ _reswitch
|
||||
MOV R3, #1
|
||||
STR R3, [R2]
|
||||
|
||||
LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
|
||||
STR R0, [R2]
|
||||
|
||||
_reswitch:
|
||||
LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
|
||||
STR R1, [R2]
|
||||
|
||||
LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =PENDSVSET_BIT
|
||||
STR R1, [R0]
|
||||
BX LR
|
||||
|
||||
/* R0 --> switch from thread stack
|
||||
* R1 --> switch to thread stack
|
||||
* psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
|
||||
*/
|
||||
.global PendSV_Handler
|
||||
.type PendSV_Handler, %function
|
||||
PendSV_Handler:
|
||||
/* disable interrupt to protect context switch */
|
||||
MRS R2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
/* get rt_thread_switch_interrupt_flag */
|
||||
LDR R0, =rt_thread_switch_interrupt_flag
|
||||
LDR R1, [R0]
|
||||
CBZ R1, pendsv_exit /* pendsv aLReady handled */
|
||||
|
||||
/* clear rt_thread_switch_interrupt_flag to 0 */
|
||||
MOV R1, #0
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =rt_interrupt_from_thread
|
||||
LDR R1, [R0]
|
||||
CBZ R1, switch_to_thread /* skip register save at the first time */
|
||||
|
||||
MRS R1, PSP /* get from thread stack pointer */
|
||||
STMFD R1!, {R4 - R11} /* push R4 - R11 register */
|
||||
LDR R0, [R0]
|
||||
STR R1, [R0] /* update from thread stack pointer */
|
||||
|
||||
switch_to_thread:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
LDR R1, [R1]
|
||||
LDR R1, [R1] /* load thread stack pointer */
|
||||
|
||||
LDMFD R1!, {R4 - R11} /* pop R4 - R11 register */
|
||||
MSR PSP, R1 /* update stack pointer */
|
||||
|
||||
pendsv_exit:
|
||||
/* restore interrupt */
|
||||
MSR PRIMASK, R2
|
||||
|
||||
ORR LR, LR, #0x04
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch_to(rt_uint32 to);
|
||||
* R0 --> to
|
||||
*/
|
||||
.global rt_hw_context_switch_to
|
||||
.type rt_hw_context_switch_to, %function
|
||||
rt_hw_context_switch_to:
|
||||
LDR R1, =rt_interrupt_to_thread
|
||||
STR R0, [R1]
|
||||
|
||||
/* set from thread to 0 */
|
||||
LDR R1, =rt_interrupt_from_thread
|
||||
MOV R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* set interrupt flag to 1 */
|
||||
LDR R1, =rt_thread_switch_interrupt_flag
|
||||
MOV R0, #1
|
||||
STR R0, [R1]
|
||||
|
||||
/* set the PendSV and SysTick exception priority */
|
||||
LDR R0, =SHPR3
|
||||
LDR R1, =PENDSV_PRI_LOWEST
|
||||
LDR.W R2, [R0,#0] /* read */
|
||||
ORR R1, R1, R2 /* modify */
|
||||
STR R1, [R0] /* write-back */
|
||||
|
||||
LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */
|
||||
LDR R1, =PENDSVSET_BIT
|
||||
STR R1, [R0]
|
||||
|
||||
/* restore MSP */
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
/* enable interrupts at processor level */
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
/* never reach here! */
|
||||
|
||||
/* compatible with old version */
|
||||
.global rt_hw_interrupt_thread_switch
|
||||
.type rt_hw_interrupt_thread_switch, %function
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX LR
|
||||
NOP
|
||||
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
/* get current context */
|
||||
MRS r0, msp /* get fault context from handler. */
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp /* get fault context from thread. */
|
||||
_get_sp_done:
|
||||
|
||||
STMFD r0!, {r4 - r11} /* push r4 - r11 register */
|
||||
STMFD r0!, {lr} /* push exec_return register */
|
||||
|
||||
TST lr, #0x04 /* if(!EXC_RETURN[2]) */
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 /* update stack pointer to PSP. */
|
||||
B _update_done
|
||||
_update_msp:
|
||||
MSR msp, r0 /* update stack pointer to MSP. */
|
||||
_update_done:
|
||||
|
||||
PUSH {LR}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {LR}
|
||||
|
||||
ORR LR, LR, #0x04
|
||||
BX LR
|
||||
|
||||
/*
|
||||
* rt_uint32_t rt_hw_interrupt_check(void);
|
||||
* R0 --> state
|
||||
*/
|
||||
.global rt_hw_interrupt_check
|
||||
.type rt_hw_interrupt_check, %function
|
||||
rt_hw_interrupt_check:
|
||||
MRS R0, IPSR
|
||||
BX LR
|
||||
@@ -0,0 +1,202 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version
|
||||
; * 2009-09-27 Bernard add protect when contex switch occurs
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup cortex-m3
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
SECTION .text:CODE(2)
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch
|
||||
rt_hw_context_switch_interrupt:
|
||||
rt_hw_context_switch:
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
EXPORT PendSV_Handler
|
||||
PendSV_Handler:
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; */
|
||||
EXPORT rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
NOP
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; never reach here!
|
||||
|
||||
; compatible with old version
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
rt_hw_interrupt_thread_switch:
|
||||
BX lr
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler:
|
||||
|
||||
; get current context
|
||||
MRS r0, msp ; get fault context from handler.
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _get_sp_done
|
||||
MRS r0, psp ; get fault context from thread.
|
||||
_get_sp_done
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
;STMFD r0!, {lr} ; push exec_return register
|
||||
SUB r0, r0, #0x04
|
||||
STR lr, [r0]
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
BEQ _update_msp
|
||||
MSR psp, r0 ; update stack pointer to PSP.
|
||||
B _update_done
|
||||
_update_msp
|
||||
MSR msp, r0 ; update stack pointer to MSP.
|
||||
_update_done
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
|
||||
END
|
||||
@@ -0,0 +1,207 @@
|
||||
;/*
|
||||
; * Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Change Logs:
|
||||
; * Date Author Notes
|
||||
; * 2009-01-17 Bernard first version
|
||||
; * 2013-06-18 aozima add restore MSP feature.
|
||||
; * 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
; */
|
||||
|
||||
;/**
|
||||
; * @addtogroup CORTEX-M3
|
||||
; */
|
||||
;/*@{*/
|
||||
|
||||
SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register
|
||||
NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register
|
||||
NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2)
|
||||
NVIC_PENDSV_PRI EQU 0xFFFF0000 ; PendSV and SysTick priority value (lowest)
|
||||
NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception
|
||||
|
||||
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||
THUMB
|
||||
REQUIRE8
|
||||
PRESERVE8
|
||||
|
||||
IMPORT rt_thread_switch_interrupt_flag
|
||||
IMPORT rt_interrupt_from_thread
|
||||
IMPORT rt_interrupt_to_thread
|
||||
|
||||
;/*
|
||||
; * rt_base_t rt_hw_interrupt_disable();
|
||||
; */
|
||||
rt_hw_interrupt_disable PROC
|
||||
EXPORT rt_hw_interrupt_disable
|
||||
MRS r0, PRIMASK
|
||||
CPSID I
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_interrupt_enable(rt_base_t level);
|
||||
; */
|
||||
rt_hw_interrupt_enable PROC
|
||||
EXPORT rt_hw_interrupt_enable
|
||||
MSR PRIMASK, r0
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
|
||||
; * r0 --> from
|
||||
; * r1 --> to
|
||||
; */
|
||||
rt_hw_context_switch_interrupt
|
||||
EXPORT rt_hw_context_switch_interrupt
|
||||
rt_hw_context_switch PROC
|
||||
EXPORT rt_hw_context_switch
|
||||
|
||||
; set rt_thread_switch_interrupt_flag to 1
|
||||
LDR r2, =rt_thread_switch_interrupt_flag
|
||||
LDR r3, [r2]
|
||||
CMP r3, #1
|
||||
BEQ _reswitch
|
||||
MOV r3, #1
|
||||
STR r3, [r2]
|
||||
|
||||
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
|
||||
STR r0, [r2]
|
||||
|
||||
_reswitch
|
||||
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
|
||||
STR r1, [r2]
|
||||
|
||||
LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch)
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
BX LR
|
||||
ENDP
|
||||
|
||||
; r0 --> switch from thread stack
|
||||
; r1 --> switch to thread stack
|
||||
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
|
||||
; disable interrupt to protect context switch
|
||||
MRS r2, PRIMASK
|
||||
CPSID I
|
||||
|
||||
; get rt_thread_switch_interrupt_flag
|
||||
LDR r0, =rt_thread_switch_interrupt_flag
|
||||
LDR r1, [r0]
|
||||
CBZ r1, pendsv_exit ; pendsv already handled
|
||||
|
||||
; clear rt_thread_switch_interrupt_flag to 0
|
||||
MOV r1, #0x00
|
||||
STR r1, [r0]
|
||||
|
||||
LDR r0, =rt_interrupt_from_thread
|
||||
LDR r1, [r0]
|
||||
CBZ r1, switch_to_thread ; skip register save at the first time
|
||||
|
||||
MRS r1, psp ; get from thread stack pointer
|
||||
STMFD r1!, {r4 - r11} ; push r4 - r11 register
|
||||
LDR r0, [r0]
|
||||
STR r1, [r0] ; update from thread stack pointer
|
||||
|
||||
switch_to_thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
LDR r1, [r1]
|
||||
LDR r1, [r1] ; load thread stack pointer
|
||||
|
||||
LDMFD r1!, {r4 - r11} ; pop r4 - r11 register
|
||||
MSR psp, r1 ; update stack pointer
|
||||
|
||||
pendsv_exit
|
||||
; restore interrupt
|
||||
MSR PRIMASK, r2
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
;/*
|
||||
; * void rt_hw_context_switch_to(rt_uint32 to);
|
||||
; * r0 --> to
|
||||
; * this fucntion is used to perform the first thread switch
|
||||
; */
|
||||
rt_hw_context_switch_to PROC
|
||||
EXPORT rt_hw_context_switch_to
|
||||
; set to thread
|
||||
LDR r1, =rt_interrupt_to_thread
|
||||
STR r0, [r1]
|
||||
|
||||
; set from thread to 0
|
||||
LDR r1, =rt_interrupt_from_thread
|
||||
MOV r0, #0x0
|
||||
STR r0, [r1]
|
||||
|
||||
; set interrupt flag to 1
|
||||
LDR r1, =rt_thread_switch_interrupt_flag
|
||||
MOV r0, #1
|
||||
STR r0, [r1]
|
||||
|
||||
; set the PendSV and SysTick exception priority
|
||||
LDR r0, =NVIC_SYSPRI2
|
||||
LDR r1, =NVIC_PENDSV_PRI
|
||||
LDR.W r2, [r0,#0x00] ; read
|
||||
ORR r1,r1,r2 ; modify
|
||||
STR r1, [r0] ; write-back
|
||||
|
||||
; trigger the PendSV exception (causes context switch)
|
||||
LDR r0, =NVIC_INT_CTRL
|
||||
LDR r1, =NVIC_PENDSVSET
|
||||
STR r1, [r0]
|
||||
|
||||
; restore MSP
|
||||
LDR r0, =SCB_VTOR
|
||||
LDR r0, [r0]
|
||||
LDR r0, [r0]
|
||||
MSR msp, r0
|
||||
|
||||
; enable interrupts at processor level
|
||||
CPSIE F
|
||||
CPSIE I
|
||||
|
||||
; never reach here!
|
||||
ENDP
|
||||
|
||||
; compatible with old version
|
||||
rt_hw_interrupt_thread_switch PROC
|
||||
EXPORT rt_hw_interrupt_thread_switch
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
IMPORT rt_hw_hard_fault_exception
|
||||
EXPORT HardFault_Handler
|
||||
HardFault_Handler PROC
|
||||
|
||||
; get current context
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler.
|
||||
MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread.
|
||||
|
||||
STMFD r0!, {r4 - r11} ; push r4 - r11 register
|
||||
STMFD r0!, {lr} ; push exec_return register
|
||||
|
||||
TST lr, #0x04 ; if(!EXC_RETURN[2])
|
||||
ITE EQ
|
||||
MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP.
|
||||
MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP.
|
||||
|
||||
PUSH {lr}
|
||||
BL rt_hw_hard_fault_exception
|
||||
POP {lr}
|
||||
|
||||
ORR lr, lr, #0x04
|
||||
BX lr
|
||||
ENDP
|
||||
|
||||
ALIGN 4
|
||||
|
||||
END
|
||||
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2009-01-05 Bernard first version
|
||||
* 2011-02-14 onelife Modify for EFM32
|
||||
* 2011-06-17 onelife Merge all of the C source code into cpuport.c
|
||||
* 2012-12-23 aozima stack addr align to 8byte.
|
||||
* 2012-12-29 Bernard Add exception hook.
|
||||
* 2013-07-09 aozima enhancement hard fault exception handler.
|
||||
* 2019-07-03 yangjie add __rt_ffs() for armclang.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct exception_stack_frame
|
||||
{
|
||||
rt_uint32_t r0;
|
||||
rt_uint32_t r1;
|
||||
rt_uint32_t r2;
|
||||
rt_uint32_t r3;
|
||||
rt_uint32_t r12;
|
||||
rt_uint32_t lr;
|
||||
rt_uint32_t pc;
|
||||
rt_uint32_t psr;
|
||||
};
|
||||
|
||||
struct stack_frame
|
||||
{
|
||||
/* r4 ~ r11 register */
|
||||
rt_uint32_t r4;
|
||||
rt_uint32_t r5;
|
||||
rt_uint32_t r6;
|
||||
rt_uint32_t r7;
|
||||
rt_uint32_t r8;
|
||||
rt_uint32_t r9;
|
||||
rt_uint32_t r10;
|
||||
rt_uint32_t r11;
|
||||
|
||||
struct exception_stack_frame exception_stack_frame;
|
||||
};
|
||||
|
||||
/* flag in interrupt handling */
|
||||
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
/* exception hook */
|
||||
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
|
||||
|
||||
/**
|
||||
* This function will initialize thread stack
|
||||
*
|
||||
* @param tentry the entry of thread
|
||||
* @param parameter the parameter of entry
|
||||
* @param stack_addr the beginning stack address
|
||||
* @param texit the function will be called when thread exit
|
||||
*
|
||||
* @return stack address
|
||||
*/
|
||||
rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
void *parameter,
|
||||
rt_uint8_t *stack_addr,
|
||||
void *texit)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
rt_uint8_t *stk;
|
||||
unsigned long i;
|
||||
|
||||
stk = stack_addr + sizeof(rt_uint32_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
|
||||
stk -= sizeof(struct stack_frame);
|
||||
|
||||
stack_frame = (struct stack_frame *)stk;
|
||||
|
||||
/* init all register */
|
||||
for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
|
||||
{
|
||||
((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */
|
||||
stack_frame->exception_stack_frame.r1 = 0; /* r1 */
|
||||
stack_frame->exception_stack_frame.r2 = 0; /* r2 */
|
||||
stack_frame->exception_stack_frame.r3 = 0; /* r3 */
|
||||
stack_frame->exception_stack_frame.r12 = 0; /* r12 */
|
||||
stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */
|
||||
stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */
|
||||
stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */
|
||||
|
||||
/* return task's current stack address */
|
||||
return stk;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function set the hook, which is invoked on fault exception handling.
|
||||
*
|
||||
* @param exception_handle the exception handling hook function.
|
||||
*/
|
||||
void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context))
|
||||
{
|
||||
rt_exception_hook = exception_handle;
|
||||
}
|
||||
|
||||
#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */
|
||||
#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */
|
||||
#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */
|
||||
#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */
|
||||
#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */
|
||||
#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */
|
||||
|
||||
#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */
|
||||
#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */
|
||||
#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
static void usage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("usage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<0))
|
||||
{
|
||||
/* [0]:UNDEFINSTR */
|
||||
rt_kprintf("UNDEFINSTR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<1))
|
||||
{
|
||||
/* [1]:INVSTATE */
|
||||
rt_kprintf("INVSTATE ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<2))
|
||||
{
|
||||
/* [2]:INVPC */
|
||||
rt_kprintf("INVPC ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<3))
|
||||
{
|
||||
/* [3]:NOCP */
|
||||
rt_kprintf("NOCP ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<8))
|
||||
{
|
||||
/* [8]:UNALIGNED */
|
||||
rt_kprintf("UNALIGNED ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR & (1<<9))
|
||||
{
|
||||
/* [9]:DIVBYZERO */
|
||||
rt_kprintf("DIVBYZERO ");
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
|
||||
static void bus_fault_track(void)
|
||||
{
|
||||
rt_kprintf("bus fault:\n");
|
||||
rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IBUSERR */
|
||||
rt_kprintf("IBUSERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<1))
|
||||
{
|
||||
/* [1]:PRECISERR */
|
||||
rt_kprintf("PRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<2))
|
||||
{
|
||||
/* [2]:IMPRECISERR */
|
||||
rt_kprintf("IMPRECISERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<3))
|
||||
{
|
||||
/* [3]:UNSTKERR */
|
||||
rt_kprintf("UNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<4))
|
||||
{
|
||||
/* [4]:STKERR */
|
||||
rt_kprintf("STKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_BFSR & (1<<7))
|
||||
{
|
||||
rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_manage_fault_track(void)
|
||||
{
|
||||
rt_kprintf("mem manage fault:\n");
|
||||
rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<0))
|
||||
{
|
||||
/* [0]:IACCVIOL */
|
||||
rt_kprintf("IACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<1))
|
||||
{
|
||||
/* [1]:DACCVIOL */
|
||||
rt_kprintf("DACCVIOL ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<3))
|
||||
{
|
||||
/* [3]:MUNSTKERR */
|
||||
rt_kprintf("MUNSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<4))
|
||||
{
|
||||
/* [4]:MSTKERR */
|
||||
rt_kprintf("MSTKERR ");
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR & (1<<7))
|
||||
{
|
||||
/* [7]:MMARVALID */
|
||||
rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void hard_fault_track(void)
|
||||
{
|
||||
if(SCB_HFSR & (1UL<<1))
|
||||
{
|
||||
/* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
|
||||
rt_kprintf("failed vector fetch\n");
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<30))
|
||||
{
|
||||
/* [30]:FORCED, Indicates hard fault is taken because of bus fault,
|
||||
memory management fault, or usage fault. */
|
||||
if(SCB_CFSR_BFSR)
|
||||
{
|
||||
bus_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_MFSR)
|
||||
{
|
||||
mem_manage_fault_track();
|
||||
}
|
||||
|
||||
if(SCB_CFSR_UFSR)
|
||||
{
|
||||
usage_fault_track();
|
||||
}
|
||||
}
|
||||
|
||||
if(SCB_HFSR & (1UL<<31))
|
||||
{
|
||||
/* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
|
||||
rt_kprintf("debug event\n");
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
struct exception_info
|
||||
{
|
||||
rt_uint32_t exc_return;
|
||||
struct stack_frame stack_frame;
|
||||
};
|
||||
|
||||
/*
|
||||
* fault exception handler
|
||||
*/
|
||||
void rt_hw_hard_fault_exception(struct exception_info * exception_info)
|
||||
{
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
extern long list_thread(void);
|
||||
#endif
|
||||
struct stack_frame* context = &exception_info->stack_frame;
|
||||
|
||||
if (rt_exception_hook != RT_NULL)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_exception_hook(exception_info);
|
||||
if (result == RT_EOK)
|
||||
return;
|
||||
}
|
||||
|
||||
rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr);
|
||||
|
||||
rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);
|
||||
rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
|
||||
rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
|
||||
rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
|
||||
rt_kprintf("r04: 0x%08x\n", context->r4);
|
||||
rt_kprintf("r05: 0x%08x\n", context->r5);
|
||||
rt_kprintf("r06: 0x%08x\n", context->r6);
|
||||
rt_kprintf("r07: 0x%08x\n", context->r7);
|
||||
rt_kprintf("r08: 0x%08x\n", context->r8);
|
||||
rt_kprintf("r09: 0x%08x\n", context->r9);
|
||||
rt_kprintf("r10: 0x%08x\n", context->r10);
|
||||
rt_kprintf("r11: 0x%08x\n", context->r11);
|
||||
rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
|
||||
rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
|
||||
rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);
|
||||
|
||||
if(exception_info->exc_return & (1 << 2) )
|
||||
{
|
||||
rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name);
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("hard fault on handler\r\n\r\n");
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
hard_fault_track();
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_shutdown(void)
|
||||
{
|
||||
rt_kprintf("shutdown...\n");
|
||||
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset CPU
|
||||
*/
|
||||
RT_WEAK void rt_hw_cpu_reset(void)
|
||||
{
|
||||
SCB_AIRCR = SCB_RESET_VALUE;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPU_FFS
|
||||
/**
|
||||
* This function finds the first bit set (beginning with the least significant bit)
|
||||
* in value and return the index of that bit.
|
||||
*
|
||||
* Bits are numbered starting at 1 (the least significant bit). A return value of
|
||||
* zero from any of these functions means that the argument was zero.
|
||||
*
|
||||
* @return return the index of the first bit set. If value is 0, then this function
|
||||
* shall return 0.
|
||||
*/
|
||||
#if defined(__CC_ARM)
|
||||
__asm int __rt_ffs(int value)
|
||||
{
|
||||
CMP r0, #0x00
|
||||
BEQ exit
|
||||
|
||||
RBIT r0, r0
|
||||
CLZ r0, r0
|
||||
ADDS r0, r0, #0x01
|
||||
|
||||
exit
|
||||
BX lr
|
||||
}
|
||||
#elif defined(__clang__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
__asm volatile(
|
||||
"CMP r0, #0x00 \n"
|
||||
"BEQ 1f \n"
|
||||
|
||||
"RBIT r0, r0 \n"
|
||||
"CLZ r0, r0 \n"
|
||||
"ADDS r0, r0, #0x01 \n"
|
||||
|
||||
"1: \n"
|
||||
|
||||
: "=r"(value)
|
||||
: "r"(value)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
if (value == 0) return value;
|
||||
|
||||
asm("RBIT %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("CLZ %0, %1" : "=r"(value) : "r"(value));
|
||||
asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value));
|
||||
|
||||
return value;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
int __rt_ffs(int value)
|
||||
{
|
||||
return __builtin_ffs(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Loaded 100 of 2473 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user