-
2019-08-01 19:45:11
首先看一下vector_irq的定义,此每处理器数组变量,保存每个处理器上中断向量所对应的中断号,其以中断向量值为索引。系统中定义了256个中断向量。相关代码如下:
typedef int vector_irq_t[NR_VECTORS]; DEFINE_PER_CPU(vector_irq_t, vector_irq) = { [0 ... NR_VECTORS - 1] = VECTOR_UNDEFINED, }; #define NR_VECTORS 256
另一个是used_vector的定义,其为一个位图变量,用来标记系统中已经使用的中断向量。
DECLARE_BITMAP(used_vectors, NR_VECTORS);
中断向量初始化
中断初始化入口函数init_IRQ。为支持传统的PIC类型的终端控制器,如8259,内核预留了IRQ0_VECTOR 到 IRQ15_VECTOR 共16个中断向量,分别对应IRQ号0到15。在初始化时,也不是全部预留这16个中断向量,而是根据检测到的传统PIC中断控制器所支持中断数量在预留,有可能小于16个。x86_init.irqs.intr_init()指针对应的为native_init_IRQ函数,接下来介绍。
void __init init_IRQ(void) { for (i = 0; i < nr_legacy_irqs(); i++) per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; x86_init.irqs.intr_init(); }
函数apic_intr_init负责分配系统自身所需的中断向量。x86架构的IDT中断描述表可用的外部中断向量由0x20(FIRST_EXTERNAL_VECTOR)开始,其中0x80(IA32_SYSCALL_VECTOR)为系统调用所用的中断向量;0x30-0x3f共16个中断向量保留给ISA使用。interrupt函数参见文件arch/x86/kernel/entry_64.S中的定义,表示中断处理程序的入口地址,for_each_clear_bit_from循环将所有未使用的中断向量的处理程序入口设定为interrupt的相应偏移。最后对于传统的中断控制器,irq2用作两片控制器的级联。
void __init native_init_IRQ(void) { apic_intr_init(); i = FIRST_EXTERNAL_VECTOR; for_each_clear_bit_from(i, used_vectors, NR_VECTORS) { set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); } if (!acpi_ioapic && !of_ioapic) setup_irq(2, &irq2); }
系统中断向量分配
函数apic_intr_init。首先分配SMP相关的中断向量,参见函数smp_intr_init,随后是分配其他的向量。这些中断向量值由大到小分配,首先是:SPURIOUS_APIC_VECTOR(0xff),目前最小的是:LOCAL_TIMER_VECTOR(0xef)。内核中定义了变量first_system_vector表示当前系统中断向量的最小值。
static void __init apic_intr_init(void) { smp_intr_init(); #ifdef CONFIG_X86_THERMAL_VECTOR alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); } static void __init smp_intr_init(void) { #ifdef CONFIG_SMP #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); }
alloc_intr_gate宏由alloc_system_vector和set_intr_gate两个函数组成。前者为注册的系统中断向量设置used_vectors中的使用标志,并且更新系统最小向量值:first_system_vector。后者set_intr_gate函数设置处理器的IDT表。
static inline void alloc_system_vector(int vector) { if (!test_bit(vector, used_vectors)) { set_bit(vector, used_vectors); if (first_system_vector > vector) first_system_vector = vector; } else { BUG(); } } #define alloc_intr_gate(n, addr) \ do { \ alloc_system_vector(n); \ set_intr_gate(n, addr); \ } while (0)
外部中断向量分配
由如下函数irq_alloc_hwirqs可见,首先调用函数__irq_alloc_descs分配中断号,内核中已经使用的中断号标记在全局位图变量allocated_irqs中,函数的第一个参数表示期望的中断号,-1表示由系统来选择中断号。系统将在allocated_irqs位图中选择一个不为零的位返回,作为新的中断号。
函数arch_setup_hwirq负责为中断号查找合适的中断向量。注意在执行过程中出现错误的话,函数将执行回退处理,包括由函数irq_free_descs复位之前分配中断号时设置的allocated_irqs中的位。arch_teardown_hwirq函数是对应arch_setup_hwirq函数的清理函数。
unsigned int irq_alloc_hwirqs(int cnt, int node) { int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL); if (irq < 0) return 0; for (i = irq; cnt > 0; i++, cnt--) { if (arch_setup_hwirq(i, node)) goto err; irq_clear_status_flags(i, _IRQ_NOREQUEST); } return irq; err: for (i--; i >= irq; i--) { irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); arch_teardown_hwirq(i); } irq_free_descs(irq, cnt); return 0; }
arch_setup_hwirq函数的主体是由__assign_irq_vector函数完成,其定义如下。由于终端级别是由中断向量后4位决定的,而本地的APIC不能够很好的处理多个同级别的中断,所以内核以2的4次方,即16为区间,进行中断向量的分配。
使用静态变量current_vector和current_offset分别记录当前的区间起始值和区间内偏移。第一次分配中断向量时,current_vector为33,偏移值为1,所以第一个可供分配的中断向量为34。
static int __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask) { static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START; static int current_offset = VECTOR_OFFSET_START % 16;
以下的中断向量查找由两个循环组成。第一个循环遍历中断可用的处理器列表,由APIC控制器的可用处理器列表和在线处理器列表中第一个同时置位的处理器开始,第二个循环(内部循环)遍历所有可用的中断向量vector,如果没有合适的选择,即vector的值又回到了最初的current_vector,进行第二次循环,遍历第二个可用的处理器。
获取第二个可用处理器的算法为:1)当前分配的处理器域domain(处理器列表),与老的域值old_domain进行或操作;2)将上一步的结果和APIC处理器列表进行与操作;3)在第二步所得结果和在线处理器列表中获取第一个同时置位的处理器。此即下一个循环要遍历的处理器。
1287 cpumask_clear(cfg->old_domain); 1288 cpu = cpumask_first_and(mask, cpu_online_mask); 1289 while (cpu < nr_cpu_ids) { 1290 int new_cpu, vector, offset; 1291 1294 apic->vector_allocation_domain(cpu, tmp_mask, mask); 1335 if (unlikely(current_vector == vector)) { 1340 cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask); 1345 cpumask_andnot(tmp_mask, mask, cfg->old_domain); 1348 cpu = cpumask_first_and(tmp_mask, cpu_online_mask); 1350 continue; 1351 }
内部的循环由标签和goto语句组成。每次遍历16长度的区间中的第一个偏移向量值,一直遍历完所有的区间。之后,当vector向量值大于最大可用向量值first_system_vector时,重新由第一个区间的第二个偏移值开始遍历。
如果遍历的向量值没有被使用,即used_vectors位图没有置位。并且,tmp_mask中的所有有效处理器上vector_irq映射还没有被占用,表明此中断向量可用。
1324 vector = current_vector; 1325 offset = current_offset; 1326 next: 1329 vector += 16; 1330 if (vector >= first_system_vector) { 1331 offset = (offset + 1) % 16; 1332 vector = FIRST_EXTERNAL_VECTOR + offset; 1333 } 1334 1335 if (unlikely(current_vector == vector)) { 1340 cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask); 1345 cpumask_andnot(tmp_mask, mask, cfg->old_domain); 1348 cpu = cpumask_first_and(tmp_mask, cpu_online_mask); 1350 continue; 1351 } 1352 1353 if (test_bit(vector, used_vectors)) 1355 goto next; 1357 1358 for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) { 1359 if (per_cpu(vector_irq, new_cpu)[vector] > VECTOR_UNDEFINED) 1360 goto next; 1361 }
成功找到可用的中断向量之后,更新静态的current_vector和current_offset的值,并更新tmp_mask中所有处理器的vector_irq中断向量和中断号映射值,写入分配的irq中断号,表明此中断向量已被占用。使用cfg中的domain成员记录有效的处理器列表。
除去第一次申请中断向量外,系统也可能动态的调整中断向量,及为其服务的处理器列表,old_domain用来保存调整前的处理器列表,move_in_progress表示是否正处于调整期间,调整结束之后old_domain为空,move_in_progress也值为0。
1362 /* Found one! */ 1363 current_vector = vector; 1364 current_offset = offset; 1365 if (cfg->vector) { 1371 cpumask_copy(cfg->old_domain, cfg->domain); 1374 cfg->move_in_progress = cpumask_intersects(cfg->old_domain, cpu_online_mask); 1377 } 1380 for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) 1381 per_cpu(vector_irq, new_cpu)[vector] = irq; 1382 cfg->vector = vector; 1383 cpumask_copy(cfg->domain, tmp_mask); 1387 1388 err = 0; 1389 break;
另外,在中断调整时,如果服务的处理器列表调整前后一致,直接跳出循环(cpumask_equal(tmp_mask, cfg->domain))。如果新的处理器列表是调整前处理器列表的子集,移除多余的处理器,并更新domain为调整之后的处理器列表。
1294 apic->vector_allocation_domain(cpu, tmp_mask, mask); 1295 1296 if (cpumask_subset(tmp_mask, cfg->domain)) { 1297 err = 0; 1303 if (cpumask_equal(tmp_mask, cfg->domain)) 1304 break; 1305 /* 1306 * New cpumask using the vector is a proper subset of the current in use mask. So cleanup the vector 1308 * allocation for the members that are not used anymore. 1309 */ 1310 cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask); 1313 1314 cfg->move_in_progress = cpumask_intersects(cfg->old_domain, cpu_online_mask); 1317 cpumask_and(cfg->domain, cfg->domain, tmp_mask); 1320 1321 break; 1322 }
以上的介绍打乱了代码的顺序,以行号为准。
内核版本:3.10.0
更多相关内容 -
在IAR环境下,lpc1788用户程序的地址及中断向量设置
2020-07-18 16:05:10但当系统中有两个程序时,例如带bootloader的系统,则应用程序的运行需要通过bootloader跳转,和bootloader相比,应用程序的地址和中断向量表地址都发生改变,如何告诉编译器来分配bootloader和应用程序在flash中的... -
无中断向量重定位单片机中实现IAP和APP中断的方法
2021-07-06 18:12:37独创了一种基于RAM中转的中断跳转方法,该方法以软件形式实现了单片机的中断向量重定位功能,实现了在应用中编程,克服了某类普通经济型单片机无法通过硬件寄存器设置中断跳转地址来实现跳转的局限性,使得这类... -
中断向量
2019-06-26 11:11:56中断向量是什么1. 目标
1)中断向量概念
2)中断向量的加载
3)中断硬件准备
3) 中断处理服务vector_irq的定义
4) 中断处理服务 vector_irq的处理流程
5) 如果进入中断前是svc模式处理场景
6)如果进入中断钱是usr模式处理场景
内核版本:4.4.172. 中断向量表
中断向量表中保存所有中断向量的入口,__vectors_start是一个中断向量表,其中的一项:W(b) vector_irq,就是放的一个跳转指令,跳转到vector_irq。
在arch/arm/kernel/entry-armv.S中的__vectors_start的定义如下:
1209 __vectors_start: 1210 W(b) vector_rst 1211 W(b) vector_und 1212 W(ldr) pc, __vectors_start + 0x1000 1213 W(b) vector_pabt 1214 W(b) vector_dabt 1215 W(b) vector_addrexcptn 1216 W(b) vector_irq //b是跳转指令 1217 W(b) vector_fiq 1218 1219 .data
地址 异常种类 0xffff 0000 复位 0xffff 0004 未定义指令 0xffff 0008 软中断(SWI) 0xffff 000c prefetch abort 0xffff 0010 data abort 0xffff 0014 address exception 0xffff 0018 irq 0xffff 001c fiq 3. 中断向量加载
arch/arm/kernel/traps.c中,early_trap_init函数中:
802 void __init early_trap_init(void *vectors_base) 803 { 804 #ifndef CONFIG_CPU_V7M 805 unsigned long vectors = (unsigned long)vectors_base; 806 extern char __stubs_start[], __stubs_end[]; 807 extern char __vectors_start[], __vectors_end[]; 808 unsigned i; 809 810 vectors_page = vectors_base; 811 812 /* 813 * Poison the vectors page with an undefined instruction. This 814 * instruction is chosen to be undefined for both ARM and Thumb 815 * ISAs. The Thumb version is an undefined instruction with a 816 * branch back to the undefined instruction. 817 */ 818 for (i = 0; i < PAGE_SIZE / sizeof(u32); i++) 819 ((u32 *)vectors_base)[i] = 0xe7fddef1; 820 821 /* 822 * Copy the vectors, stubs and kuser helpers (in entry-armv.S) 823 * into the vector page, mapped at 0xffff0000, and ensure these 824 * are visible to the instruction stream. 825 */ 826 memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); 827 memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start); 828 printk(KERN_ERR "tom __vectors_start=%x __vectors_end=%x\n",__vectors_start,__vectors_end); printk(KERN_ERR "tom %x %x %x %x\n",*((char *)vectors+24),*((char *)vectors+25),*((char *)vectors+26),*((char *)vectors+27)); 838 kuser_init(vectors_base); 839 840 flush_icache_range(vectors, vectors + PAGE_SIZE * 2); 841 #else /* ifndef CONFIG_CPU_V7M */ 842 /* 843 * on V7-M there is no need to copy the vector table to a dedicated 844 * memory area. The address is configurable and so a table in the kernel 845 * image can be used. 846 */ 847 #endif 848 }
打印信息是:
tom __vectors_start=80630000 __vectors_end=80630020 tom 0 4 0 ea
在System.map中有__vectors_start的符号是0x80630000 ,__vectors_end是 0x80630020和打印信息一致。
W(b) vector_irq在内存的内容分别是: 0x00 0x04 0x00 0xea,这些是机器码,转换为整数是:0xea000400,0xea是跳转b的机器码,0x400是偏移量,怎么算出偏移量呢?
在objdump -d vmlinux中输出信息中:
- 场景是:程序中执行到0x18: b vector_irq,跳转到0x1020中的vector_irq中的偏移量怎么算?
偏移量公式: (目标地址 - 指令地址 - 8)/ 4 = 偏移
则: (0x1020-0x18-8)/4=0x400
2)静态分析vmlinux中b vector_irq的机器码就是0xea00400,和内存运行时的内容一样的。
3 vector_irq定义
vector_stub的定义如下:
1027 .macro vector_stub, name, mode, correction=0 //定义vector_stub有3个参数name,mode和correction 1028 .align 5 1030 vector_\name: 1031 .if \correction 1032 sub lr, lr, #\correction 1033 .endif 1034 1035 @ 1036 @ Save r0, lr_<exception> (parent PC) and spsr_<exception> 1037 @ (parent CPSR) 1038 @ 1039 stmia sp, {r0, lr} @ save r0, lr 1040 mrs lr, spsr 1041 str lr, [sp, #8] @ save spsr 1042 1043 @ 1044 @ Prepare for SVC32 mode. IRQs remain disabled. 1045 @ 1046 mrs r0, cpsr 1047 eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE) 1048 msr spsr_cxsf, r0 1049 1050 @ 1051 @ the branch table must immediately follow this code 1052 @ 1053 and lr, lr, #0x0f 1054 THUMB( adr r0, 1f ) 1055 THUMB( ldr lr, [r0, lr, lsl #2] ) 1056 mov r0, sp 1057 ARM( ldr lr, [pc, lr, lsl #2] ) 1058 movs pc, lr @ branch to handler in SVC mode 1059 ENDPROC(vector_\name)
vector_irq的定义如下:
1080 vector_stub irq, IRQ_MODE, 4 1081 1082 .long __irq_usr @ 0 (USR_26 / USR_32) 1083 .long __irq_invalid @ 1 (FIQ_26 / FIQ_32) 1084 .long __irq_invalid @ 2 (IRQ_26 / IRQ_32) 1085 .long __irq_svc @ 3 (SVC_26 / SVC_32) 1086 .long __irq_invalid @ 4 1087 .long __irq_invalid @ 5 1088 .long __irq_invalid @ 6 1089 .long __irq_invalid @ 7 1090 .long __irq_invalid @ 8 1091 .long __irq_invalid @ 9 1092 .long __irq_invalid @ a 1093 .long __irq_invalid @ b 1094 .long __irq_invalid @ c 1095 .long __irq_invalid @ d 1096 .long __irq_invalid @ e 1097 .long __irq_invalid @ f 1098
中断硬件准备
当一切准备好之后,一旦打开处理器的全局中断就可以处理来自外设的各种中断事件了。
当外设(SOC内部或者外部都可以)检测到了中断事件,就会通过interrupt requestion line上的电平或者边沿(上升沿或者下降沿或者both)通知到该外设连接到的那个中断控制器,而中断控制器就会在多个处理器中选择一个,并把该中断通过IRQ(或者FIQ,本文不讨论FIQ的情况)分发给该processor。ARM处理器感知到了中断事件后,会进行下面一系列的动作:
- 修改CPSR(Current Program Status Register)寄存器中的M[4:0]。改变CPSR中M[4:0],把模式切换成IRQ MODE模式。
2)保存发生中断那一点的CPSR值(step 1之前的状态)和PC值。(比如在用户空间,就保存用户空间的CPSR和PC;在内核空间,就保存内核空间的CPSR和PC)
2.1 中断那一刻的CPSR,保存到IRQ MODE的SPSR中
2.3 中断那一一刻的PC,保存到LR_IRQ中
对于thumb state,lr_irq = PC
对于ARM state,lr_irq = PC - 4
3、mask IRQ exception。也就是设定CPSR.I = 1
4、设定PC值为IRQ exception vector。
系统现在从发生中断之前的模式(比如用户或者内核模式)切换成IRQ模式。
struct stack {
u32 irq[3];
u32 abt[3];
u32 und[3];
} ____cacheline_aligned;static struct stack stacks[NR_CPUS];
4. vector_irq的处理流程
跳转到vector_irq模式,这个模式下 lr_irq保存发生中断时刻的PC 指针,IRQ_SPSR保存发生中断时刻的CPSR。
1)lr_irq= PC -4 (中断时刻PC寄存器) IRQ_SPSR= CPSR(中断时刻的CPSR)
2)在cpu_init中SP_IRQ指向stacks->irq地址,通过stmia sp, {r0, lr} 指令,stacks->irq[0]=r0(中断前的r0),stacks->irq[1]=LR_IRQ=PC-8(中断时刻下一条要执行的命令),通过 mrs lr, spsr和str lr, [sp, #8],stacks->irq[2]=LR_SPSR=CPSR(中断时刻的CPSR)
3)把SP_IRQ,存放到r0中。
4)PC设置为根据发生中断时刻的状态的处理函数地址,并且把IRQ模式切换为SVC模式。1030 vector_\name: 1031 .if 4 1032 sub lr, lr, 4 // /*计算返回地址(在arm流水线中,lr=pc+8,但是pc+4只译码没有执行,所以lr=lr-4) */ 1033 .endif 1034 1035 @ 1036 @ Save r0, lr_<exception> (parent PC) and spsr_<exception> 1037 @ (parent CPSR) 1038 @ 1039 stmia sp, {r0, lr} @ save r0, lr //把r0和lr寄存器的内容保存到sp寄存器保存的地址中 1040 mrs lr, spsr //把状态寄存器spsr的内容保存到lr寄存器器中 1041 str lr, [sp, #8] @ save spsr // 将lr的内容保存到SP指向的地址加上8个字节后的地址中,就是栈指针SP+8保存的内容是spsr。 1042 1043 @ 1044 @ Prepare for SVC32 mode. IRQs remain disabled. 1045 @ 1046 mrs r0, cpsr //将cpsr的寄存器的值保存到r0寄存器中 1047 eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE) //mode=IRQ_MODE=0x00000012 SVC_MODE=0x13 PSR_ISETSTATE=0x20 // #(\mode ^ SVC_MODE | PSR_ISETSTATE) =0x12^0x13|0x20=0x1|0x20=0x21 //eor是异或,r0和0x21异或后,保存到r0中,就是反转bit0和bit5,也就是把CPSR寄存器中的bit0和bit5反转后,保存到r0寄存器中。 1048 msr spsr_cxsf, r0 //把r0寄存器中的内容给SPSR,也就是把寄存器CPSR的bit0和bit5反转后,保存到SPSR寄存器。 //之前是THUMB模式转换为ARM模式,IRQ模式转换为SVC模式 1049 1050 @ 1051 @ the branch table must immediately follow this code 1052 @ 1053 and lr, lr, #0x0f // 把lr寄存器中的内容保留bit3-bit0。 就是把spsr的模式位保存下来 就是在进入中断模式前,CPSR就是进中断的模式存到CPSR中。 1054 THUMB( adr r0, 1f ) //THUMB是在THUMB模式下才执行的命令 1055 THUMB( ldr lr, [r0, lr, lsl #2] ) 1056 mov r0, sp //把sp占地保存到r0中。 1057 ARM( ldr lr, [pc, lr, lsl #2] ) /如果进入中断前是usr,则lr=0 如果是SVC,则lr=3 1058 movs pc, lr @ branch to handler in SVC mode //此时已经切换成SVC模式 1059 ENDPROC(vector_\name)
问题1:
THUMB或者ARM宏在哪种模式下执行?THUMB宏在THUMB模式下执行。
ARM宏在 ARM模式下执行。问题2:
1054 THUMB( adr r0, 1f ) //THUMB是在THUMB模式下才执行的命令 1055 THUMB( ldr lr, [r0, lr, lsl #2] )
如果lr=0,则ldr lr,[r0,lr,lsl #2]后,lr=r0+lr*4=r0,因为lr是标签1的地址,但是1:的 入口地址为什么是.long __irq_usr?
因为1:和__irq_usr之间的代码不占空间。其他
1.1 SWI异常
在__vectors_start中W(ldr) pc, __vectors_start + 0x1000 ,指的软中断SWI。
如下图中所示,在System.map中查看,可以看到 __vectors_start + 0x1000,也就是 __stubs_start。
查看__stubs_start的定义如下,可以看到__stubs_start指向vector_swi标签。1067 __stubs_start: 1068 @ This must be the first word 1069 .word vector_swi
1.2 CPSR寄存器
M[4:0] 模式 0b10000 用户 0b10001 FIQ 0b10010 IRQ 0b10011 管理模式 0b10111 中止 0b11011 未定义 0b11011 系统 bit5 工作状态 1 Thumb 0 ARM 注:
所有处理器模式下都可访问当前程序状态寄存器CPSR。CPSR中包含条件码标志、中断禁止位、当前处理器模式以及其他状态和控制信息。在每种异常模式下都有一个对用的程序状态寄存器SPSR。当异常出现时,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。c - control field mask byte(xPSR[7:0]) x - extension field mask byte(xPSR[15:8]) s - status field mask byte(xPSR[23:16) f - flags field mask byte(xPSR[31:24]). 老式声明方式:cpsr_flg,cpsr_all在ADS中已经不在支持 cpsr_flg对应cpsr_f cpsr_all对应cpsr_cxsf
参考
分析在linux中的中断是如何运行的,以及中断3大结构体:irq_desc、irq_chip、irqaction
ARM中断表与响应流程
Linux系统调用过程中user栈的保存与恢复
linux中断中(异常向量详解) - 场景是:程序中执行到0x18: b vector_irq,跳转到0x1020中的vector_irq中的偏移量怎么算?
-
ARM中断向量两种设置方法
2020-07-25 20:43:41在32位ARM系统中,一般都是在中断向量表中放置一条分支指令或PC寄存器加载指令,实现程序跳转到中断服务例程的功能。 -
无中断向量重定位单片机中实现IAP和APP中断的方法.pdf
2021-07-12 16:56:23无中断向量重定位单片机中实现IAP和APP中断的方法.pdf -
基于C语言设置TMS320 DSP中断向量表_设某中断向量在中断向量表中
2020-08-15 00:17:56基于 C 语言设置 TMS320 DSP 中断向量表 摘要 随着 DSP 芯片 应用 的不断深入用 C 语言开发 DSP 芯片不仅可以使 DSP 芯 片的开发速度大大提高也使得程序的修改和移植变得十分方便C 语言设置 TMS320 系 列 DSP 中断向... -
8086中断向量
2022-04-10 15:46:23微机原理 | 8086中断向量通俗易懂,留着复习用
8086共有
=256个不同的中断源,每一个中断源都有唯一的一个中断识别号,即中断类型码。
每一个中断类型码对应着一个中断向量,本质上来说中断向量就是中断服务子程序的唯一确定的一个入口地址,这个地址由中断服务子程序的段地址CS和偏移地址IP组成,共占内存4B(CS、IP均为16位,分别占两个字节)。中断向量的入口地址按照中断类型码的顺序存放在一段连续排列的存储区域内,这个存储区域就称为中断向量表。
8086的中断向量表占用了256*4=1KB的地址空间(00000H~003FFH),故8086的中断向量表位的起始地址为00000H,在微机系统初始化的时候,系统将中断源(0~255)的中断服务子程序的入口地址(即中断向量)按顺序填写在中断向量表中。
其中,中断向量类型码为n的中断向量在表中的逻辑地址为0000:4n。这里需要补充一个知识点:
逻辑地址=段地址:偏移地址
物理地址=段地址
10H+偏移地址 (7018H*10H=70180H)
逻辑地址中的4n即该中断向量在表中的存放地址(00000H~003FFH)。
在某度看到了这张表,是我认为最直接最清晰的表了,如下:
中断向量的存放方式:低地址的两字节存放中断服务子程序入口地址的偏移地址IP,高地址的两字节存放入口地址的段基址CS。
IP、CS地址具体存放方式:高八位放高地址,低八位放低地址。(地址编号大的为高地址,反之低地址,如0000H~003FFH依次从低地址到高地址)
再补充个知识点:高、低字节 &大小端模式
大端、小端说明的是数据的组织方式。
低字节放在高地址,高字节放在低地址称为大端模式,
高字节放在高地址,低字节放在低地址称为小端模式。
eg.一个十六进制的数FF1A,高字节是FF,低字节是1A。
总结来说就是左边是高字节,右边是低字节
8086系统的数据组织方式属于小端模式。
来看个例题:
8086中,中断类型码为 18H 的中断向量存放在内存中的 4 个字节单元中,其中的字节单元内容从低字节到高字节依次为 1AH、2BH、3CH、4DH, 则 18H 号中断服务程序入口地址是多少?
4D3C:2B1A
-
嵌入式系统/ARM技术中的PIE中断向量的分配
2020-11-12 23:22:03PIE支持的96个中断,每个中断都有自己的中断向量存放在RAM中,构成整个系统的中断向量表,如表所列,用户可以根据需要适当地对中断向量表进行调整。在响应中断时,CPU将自动地从中断向量表中获取相应的中断向量。CPU... -
嵌入式系统/ARM技术中的PIE中断向量的映射方式
2020-11-12 23:23:07在F281x DSP中采用外设中断扩展模块(Peripheral Interrupt Expansion,PIE)解决上述问题。外设中断扩展模块实质上是将中断向量表范围扩展...中断向量映射主要由以下位/信号来控制。 该位在状态寄存器1(ST1)的位 -
51单片机内核的中断及中断向量基础知识
2021-05-22 03:32:3451内核的最基础的中断源请求有外部中断、定时器中断和串口中断,这也是学习和开发者最长用的。当然还有其他的中断源,比如ADC、SPI、PWM等。以外部中断0为例,在编程中常使用的方式为:void INT0()interrupt 0 using...51内核的最基础的中断源请求有外部中断、定时器中断和串口中断,这也是学习和开发者最长用的。当然还有其他的中断源,比如ADC、SPI、PWM等。以外部中断0为例,在编程中常使用的方式为:
void INT0()interrupt 0 using 1
{
……
}
在这里特别做上笔记:其中前面的void INT0() 只是代表一个普通没有形参的函数而已,函数名写成什么都是可以的,这个到不重要。那么后面的就一个一个词的扣把:(2-1-i-c-中国-电子网,防抓取)
其中 interrupt n 组成一组,n用来指明中断号,在函数后使用了interrupt关键字后,就会自动的生成中断向量,51内核中断号如下图,这是我今天查的正在使用的MCU:
例如:
12
interrupt 1 指明是定时器中断0;
interrupt 2 指明是外部中断1;
interrupt 3 指明是定时器中断1
。。。
对于51内核的MCU,不同厂家及不同型号的内部资源会有所不同,上图是我正在开发的一款中颖SH88F516单片机,由上图可见内部资源还算可以,能够满足一般的产品。后面的using n 指的是使用第n组寄存器。这个之前我在使用的过程中往往忽略了这个,也没有出现什么问题。但是今天注意到这个问题,查完资料后用上发现效果还不如不用,很有肯能是没有把这个知识用好的原因把。对比之后给我的感觉是在使用C语言写程序时,能不用就不用吧。查资料解释说假如在中断函数中使用了using n,中断不再保存R0-R7的值,这也就意味着假如一个高优先级的中断及一个低优先级的中断同时使用了using n,而这个n恰恰相等,那就等着哭把,因为这个BUG还真不是那么好找出来的(今天我就遇到了这个问题)。21ic整理
其次就是中断优先级的问题了,如图上面的中断表,在右侧第二栏标的很清楚,除了复位之外,就数外部中断0优先级最高了,依次往下排列,那么问题来了,今天刚好就碰到了需要串口0的优先级比定时器0的优先级高。没办法,只好接着啃数据手册,还好这寄存器不多,一会就查到了下表和相关的描述:
所以按照描述修改下优先级就可以达到目的了。
总结:用到回过头来用到51的中断,发现有些东西在之前学习的时候并没有太在意,导致现在在开发产品上使用的时候不清楚用途。因为工作跟学习性质是不一样的,作为开发者的角度来说,质量往往是第一要求。同时会接触到很多新鲜的事物和技术,但是话又说回来了,最基本的知识还是需要打牢。
-
中断源、中断向量、矢量中断、中断向量表
2020-06-29 13:40:58问:What is interrupt? 百度百科:中断是指在计算机执行程序的过程中,...在某些计算机中,中断向量的位置存放一条跳转到中断服务程序入口地址的跳转指令。 中断向量地址:内存中存放中断服务程序入口地址的地址 ... -
BootLoader中断向量重定位
2020-02-01 11:58:32因为中断向量重定位是在main函数中完成的,重定位中断向量之前的中断向量依然执行BootLoader中的中断向量表,main函数中完成中断向量重定位后如果再发生中断,那么就执行重定位后的中断向量表 ... -
AD测试程序中断向量代码
2020-11-13 08:59:09AD测试程序中断向量代码 欢迎转载,信息来源维库电子市场网(www.dzsc.com) 来源:ks99 -
什么是中断?什么是中断向量?中断向量表的地址范围?
2020-11-30 23:22:19什么是中断向量?中断向量表的地址范围? 答:中断就是CPU在执行当前程序时由于内外部事件引起CPU暂时停止当前正在执行的程序而转向执行请求CPU暂时停止的内外部事件的服务程序,该程序处理完后又返回继续执行被停止... -
中断向量,中断向量表 ,中断服务函数
2019-07-29 12:31:52所谓中断是指CPU在正常执行程序的过程中,由于内部/外部事件的触发或由程序的预先安排,引起CPU暂时...中断向量:中断的地址的变量; 中断向量表:中断类型号与相应中断源的中断处理程序入口地址之间的连接表; ... -
keil 51 使用C语言中断向量.doc
2021-05-21 14:42:30keil 51 使用C语言中断向量keil 51 使用C语言中断向量中断源的矢量位置中断源 Keil中断编号 矢量地址最高优先级 6 0x0033外部中断0 0 0x0003定时器0溢出 1 ... -
中断向量与向量地址(计算机组成原理)
2019-10-07 20:23:40中断向量与向量地址 中断号——中段的编号 什么是中断向量?我们可以把它理解成中断服务程序的入口地址。 比如说在 x86 系列当中,我们可以把中断向量理解成中断服务程序的段地址和偏移量组成的一个向量。 有的时候... -
在IAR环境下用户程序的地址及中断向量设置
2013-02-20 17:38:22在IAR环境下用户程序的地址及中断向量设置,在IAR环境下用户程序的地址及中断向量设置 -
STM32中断向量嵌套NVIC理解
2020-08-09 20:34:52STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。 -
DOS汇编练习(6)——中断向量(DEBUG调试实例超详细~)
2020-12-16 11:58:07中断向量为:编程将中断向量类型21H所对应的中断向量从中断向量表中取出来分别放在 SI 和 BP中。(直接用 MOV 指令即可) CODE SEGMENT ASSUME CS:CODE START: XOR AX,AX ;AX清空 MOV DS,AX ;DS不可直接 MOV 立即... -
《微机原理与接口》作业一(中断向量+物理地址)
2022-03-26 15:12:33中断类型号为32H的中断向量存放在内存哪里(指明段地址和偏移地址的范围)?如果32H的中断处理子程序从13A4H:25B0H开始,中断向量应怎样存放(指明该中断的中断向量表中每个字节保存的内容)? 32H*4=0C8H, 中断... -
汇编实验三——中断及查看中断向量地址
2019-11-20 14:13:24功能:程序终止产生中断,所以我们可以写一个内存有问题的子程序,调用它就会产生一个 0H 中断 例如:200H / 0H 等于无穷,导致程序内存溢出终止,产生 0H 号中断 key_I: MOV AX,200H ;程序错误中断0(200H / 0... -
计算机组成:中断向量的相关计算
2019-05-25 16:19:36中断向量的相关计算 中断码 0~255一个256个中断码,一个中断码占4字节。 1号中断向量:00000H~00003H。比如中断码15H,那么起始的地址:15H × 4 = 00054H(可以转换成10进制计算。注意题目要求的格式是否要前面... -
IC基础知识(十)中断向量地址
2020-12-24 09:15:42中断向量地址 -
STM32中断向量偏移
2019-01-25 11:26:22总结一下在IAP升级中APP程序的中断向量表的偏移 1. 关于APP程序的中断向量表地址偏移(三种方法,stm32F2与F4系列通用。三种方法本质一样只是看到网上的各种例程的表现形式不一样) ① 直接操作寄存器 在APP程序的... -
msp430——学习4—— TA0IV 中断向量发生器-ta_3
2021-08-23 09:27:472:中断矢量发生器(TAIV, Interrupt Vector Generator): TACCR1 CCIFG、TACCR2 CCIFG和TAIFG标志被按优先级排序并组合为单个中断向量的来源。 中断向量寄存器TAIV用于确定哪个标志请求中断。 最高优先级使能的中断... -
STM32在线升级中断向量重定向深度剖析
2020-03-28 14:23:33原文地址 在做stm32 iap升级固件的时候通常需要多份中断向量表。比如bootloader的中断向量表在0x00000000位置,应用程序的中断向...VTOR是arm内核的一个寄存器,叫做中断向量偏移量寄存器。当系统上电启动的时候CPU...