__swi(0x00) void SwiHandle1(int …

本文详细解释了ARM体系结构中SWI指令的工作原理及其在软件开发中的应用。包括SWI指令如何触发异常、如何通过软中断号进行功能选择,以及如何在C语言中声明SWI调用等关键内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vicControl.h 有这样一句函数声明__swi(0x00) void SwiHandle1(int Handle);他的函数体在哪里?

__swi(0x00) void SwiHandle1(int Handle);其实没有函数体,执行这个语句后就自动把Handle的值赋给了R0,接着执行下面的代码。__swi(0x00)是软件中断,0为软中断指令中的24位立即数,但是通过R0寄存器来传递参数具体的函数体,当然是要在swi的中断处理程序中去找了可以在复位时的异常向量表里面找到swi中断服务程序的入口地址。

SWI 执行的流程是,先进入异常中断向量表,然后跳到向量地址处,接着一小段汇编操作,把功能号读入到一个寄存器中,然后 switch 判断这个功能号是多少,接着跳转到对应的终端服务程序,如果函数有参数,则根据ATPCS规则进行参数的传递;如只有一个参数,则用 R0 来传递,超过4个参数,超出的部分用堆栈来传递。

__swi是ADS编译器的关键字,用它做前缀可以声明一个软中断调用,格式为:
__swi(功能号)   返回值  名称 (参数列表)
功能号:即软中断指令中的24位立即数,软中断号
名  称:即调用软中断时用于描述软中断的函数名称
参  数:软中断函数的参数,根据ATPCS规则,如果软中断函数有不超过4个参数时,通过R0~R3传递,超过4个参数时用堆栈来传递。

__swi(0x00) void SwiHandle1(int Handle)。其中0x00为软中断功能号(软中断号);软中断函数名称为SwiHandle1;只有一个参数,则使用R0来传递;函数没有返回值。紧接着这句代码的是定义了4个宏,分别表示禁能IRQ函数、使能IRQ函数、禁能FIQ函数、使能IFQ函数,其实调用的软中断函数是一样的,只是参数不同而已。例如在用户程序中调用“IRQEnable( );”时,处理器会产生软中断。位于启动代码中的那些是软中断处理函数,当发生软中断时,PC被强制指向0x00000008,这个地址中存放的是软中断异常的处理函数的地址,所以程序会跳转至标号“SoftwareInterrupt ”处执行。SoftwareInterrupt 函数的功能是判断R0的值(R0的值为软中断函数传递过来的参数)是否小于4,如果小于4则跳转至标号“SwiFunction”执行,如果不是则函数返回。SwiFunction函数是一个散转函数,它的功能是根据R0的值跳转至对应的函数处执行,即如果参数为1,则函数会跳转至IRQEnable处执行,将IRQ中断使能。

 

本文件SWI.s位于ARM Executable Image for LPC2294工程模板中,故不考虑SWI触发前为Thumb态;SWI异常一旦触发,内核硬件完成:
   ♂ 进入Supervisor模式;
   ♂ 拷贝CPSR至SPSR_svc
   ♂ 拷贝异常返回地址至LR_svc
   ♂ 将0x00000008装入PC
    因此,当触发SWI软中断前内核处于Supervisor模式,SPSR_svc、LR_svc中的值将被破坏;
3、SWI指令编码中自带24bit数据作为软中断号(swi_num),因此可通过取SWI指令编码获取软中断号;LDR r0,[lr,#-4]就是这样;

4、SWI_Exception_Function函数一般采用C编码(也可汇编),采用C编码可直接套用switch根据swi_nun软中断号切换,SWI_Exception_Function函数的编制是灵活的,比如可以为带参或不带参函数;

5、一个SWI调用允许带1~4个字型参数和1~4个字型返回值,触发SWI调用时四个参数依次保存在R0~R3中,返回值也存于R0~R3内,这和ATPCS函数调用一致;

6、在C中声明一个典型的无参无返回值的SWI调用为:”__swi(0x00) void IRQEnable();“这样随时都可以使用”IRQEnable();“触发一个软中断(中断号0),其允许IRQ中断的功能必须在SWI_Exception_Function软中断处理函数中实现;

7、以下为带参数的SWI调用,SWI调用和普通函数调用一样遵循ATPCS标准,Handle参数存放在R0中:
__swi(0x01) void SwiHandle(int Handle);
#define IRQDisable()    SwiHandle(0)
#define IRQEnable()     SwiHandle(1)
#define FIQDisable()    SwiHandle(2)
#define FIQEnable()     SwiHandle(3)

 

 


#include "ucos_ii.h" #include "stm32f10x.h" #include <stdio.h> #include <stdlib.h> #define ITM_PORT (*(volatile unsigned char *)(0xe0000000)) #define DEMCR_ (*(volatile unsigned long *)(0xE000EDFC)) #define TRCENA_ 0X01000000 #define BufferLen 100 typedef struct { void (*task_func)(void *p_arg); void *pdata; OS_STK *ptos; INT8U prio; } TaskCreate; //char buffer[BufferLen]; uint8_t fputcp(char ch) { if(DEMCR_ & TRCENA_) { while(ITM_PORT == 0); ITM_PORT = ch; } else { return 0; } return 1; } uint8_t print_str(char *str) { uint32_t i; i = 0; while(1) { if (*(str+i) == '\0') { return 1; } if(fputcp(*(str+i))==0) { return 0; } i++; } } void *buffer; static void systick_init(void) { RCC_ClocksTypeDef rcc_clocks; RCC_GetClocksFreq(&rcc_clocks); *((uint32_t *)buffer)=rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC; SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC); } static void syscall_systick_init(void) { RCC_ClocksTypeDef rcc_clocks; RCC_GetClocksFreq(&rcc_clocks); *((uint32_t *)buffer)=rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC; __asm { SWI 0x02 } //SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC); } /*void syscall_OSIntExit() { __ASM { SWI 0x06 } }*/ /*void syscall_OSIntEnter() { __ASM { SWI 0x07 } }*/ void syscall_print_str(char *str) { int i=0; while(1) { if (*(str+i) == '\0') { ((char *)buffer)[i] = str[i]; break; } ((char *)buffer)[i] = str[i]; i++; } __ASM{ SWI 0x01 } } void syscall_OSTaskCreate(void (*task)(void *), void *pdata, OS_STK *ptos, INT8U prio) { TaskCreate *partfo = (TaskCreate *)buffer; partfo->task_func = task; partfo->pdata = pdata; partfo->ptos = ptos; partfo->prio = prio; __ASM { SWI 0x03 } } void syscall_OSTimeDly(int time) { *(int*)buffer=time; __ASM { SWI 0x04 } } void syscall_OSStart() { __ASM { SWI 0x05 } } void ASM_Switch_To_Unprivileged(void); //#define FIRST_TASK 1 #define SECOND_TASK 1 #ifdef FIRST_TASK int main(void) { buffer = malloc(BufferLen); ASM_Switch_To_Unprivileged(); syscall_print_str("Hello world!\n"); syscall_systick_init(); while(1){} } #endif #ifdef SECOND_TASK static OS_STK task1_stk[TASK1_STK_SIZE]; static OS_STK task2_stk[TASK2_STK_SIZE]; void task1(void *p_arg); void task2(void *p_arg); int main(void) { OSInit(); buffer = malloc(BufferLen); ASM_Switch_To_Unprivileged(); syscall_print_str("Hello world!\n"); syscall_systick_init(); syscall_OSTaskCreate(task1, (void *)0, &task1_stk[TASK1_STK_SIZE-1], TASK1_PRIO); syscall_OSTaskCreate(task2, (void *)0, &task2_stk[TASK2_STK_SIZE-1], TASK2_PRIO); syscall_OSStart(); return 0; } static void task1(void *p_arg) { for (;;) { syscall_OSTimeDly(100); syscall_print_str("Hello from Task 1!\n"); syscall_OSTimeDly(100); } } static void task2(void *p_arg) { for (;;) { syscall_OSTimeDly(100); syscall_print_str("Hello from Task 2!\n"); syscall_OSTimeDly(100); } } #endif /*END OF THE FILE*/
最新发布
06-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值