手机版
你好,游客 登录 注册
背景:
阅读新闻

GNU ARM汇编

中断汇编之嵌套中断处理

[日期:2012-08-12] 来源:Linux社区  作者:dndxhej [字体: ]

在上篇《GNU ARM汇编--(四)中断汇编之非嵌套中断处理》http://www.linuxidc.com/Linux/2012-08/68020p4.htm 中分析了最简单的中断处理的写法,再看TQ2440启动代码中的中断向量表的写法就一目了然了.今天抽时间对嵌套中断处理的学习做下整理.

嵌套中断处理的核心代码如下:

  1. ;/* 
  2. ; *  ____________________________________________________________________ 
  3. ; *  
  4. ; *  Copyright (c) 2004, Andrew N. Sloss, Chris Wright and Dominic Symes 
  5. ; *  All rights reserved. 
  6. ; *  ____________________________________________________________________ 
  7. ; *  
  8. ; *  NON-COMMERCIAL USE License 
  9. ; *   
  10. ; *  Redistribution and use in source and binary forms, with or without  
  11. ; *  modification, are permitted provided that the following conditions  
  12. ; *  are met:  
  13. ; *   
  14. ; *  1. For NON-COMMERCIAL USE only. 
  15. ; *  
  16. ; *  2. Redistributions of source code must retain the above copyright  
  17. ; *     notice, this list of conditions and the following disclaimer.  
  18. ; *  
  19. ; *  3. Redistributions in binary form must reproduce the above  
  20. ; *     copyright notice, this list of conditions and the following  
  21. ; *     disclaimer in the documentation and/or other materials provided  
  22. ; *     with the distribution.  
  23. ; *  
  24. ; *  4. All advertising materials mentioning features or use of this  
  25. ; *     software must display the following acknowledgement: 
  26. ; *  
  27. ; *     This product includes software developed by Andrew N. Sloss, 
  28. ; *     Chris Wright and Dominic Symes.  
  29. ; *  
  30. ; *   THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY  
  31. ; *   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
  32. ; *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  
  33. ; *   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE  
  34. ; *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
  35. ; *   OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
  36. ; *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  
  37. ; *   OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY  
  38. ; *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR  
  39. ; *   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  
  40. ; *   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY  
  41. ; *   OF SUCH DAMAGE.  
  42. ; *  
  43. ; *  If you have questions about this license or would like a different 
  44. ; *  license please email : 
  45. ; *  
  46. ; *  andrew@sloss.net 
  47. ; *  
  48. ; *  
  49. ; */  
  50.   
  51. ;/*********************************************************************** 
  52. ; * 
  53. ; *  Module       : nih9_9.s 
  54. ; *  Descriptions : Nested Interrupt Handler 
  55. ; *  Example      : 9.9 
  56. ; *  OS           : generic 
  57. ; *  Platform     : generic 
  58. ; *  History      : 
  59. ; * 
  60. ; *  31th December 2003 
  61. ; *  - added header 
  62. ; * 
  63. ; ***********************************************************************/  
  64.   
  65.      EXPORT nestedInterruptHandler  
  66.   
  67. Maskmd     EQU 0x1f                     ; processor mode mask  
  68. SVC32md    EQU 0x13                     ; SVC mode  
  69. I_Bit      EQU 0x80                     ; IRQ bit   
  70.   
  71. FRAME_R0   EQU 0x00           
  72. FRAME_R1   EQU FRAME_R0+4  
  73. FRAME_R2   EQU FRAME_R1+4  
  74. FRAME_R3   EQU FRAME_R2+4  
  75. FRAME_R4   EQU FRAME_R3+4  
  76. FRAME_R5   EQU FRAME_R4+4  
  77. FRAME_R6   EQU FRAME_R5+4  
  78. FRAME_R7   EQU FRAME_R6+4  
  79. FRAME_R8   EQU FRAME_R7+4  
  80. FRAME_R9   EQU FRAME_R8+4  
  81. FRAME_R10  EQU FRAME_R9+4  
  82. FRAME_R11  EQU FRAME_R10+4  
  83. FRAME_R12  EQU FRAME_R11+4  
  84. FRAME_PSR  EQU FRAME_R12+4  
  85. FRAME_LR   EQU FRAME_PSR+4  
  86. FRAME_PC   EQU FRAME_LR+4  
  87. FRAME_SIZE EQU FRAME_PC+4  
  88.   
  89.     AREA nih9_9,CODE,readonly  
  90.       
  91. nestedInterruptHandler ; instruction       state : comment        
  92.      SUB     r14,r14,#4                 ; 2 :  
  93.      STMDB   r13!,{r0-r3,r12,r14}       ; 2 : save context  
  94.      ; <insert code here>  
  95.      BL      read_RescheduleFlag        ; 3 : more processing  
  96.      CMP     r0,#0                      ; 3 : if processing?  
  97.      LDMNEIA r13!,{r0-r3,r12,pc}^       ; 4 :   then return   
  98.      MRS     r2,SPSR                    ; 5 : copy SPSR_irq  
  99.      MOV     r0,r13                     ; 5 : copy r13_irq  
  100.      ADD     r13,r13,#6*4               ; 5 : reset stack  
  101.      MRS     r1,CPSR                    ; 6 : copy CPSR  
  102.      BIC     r1,r1,#Maskmd              ; 6 :  
  103.      ORR     r1,r1,#SVC32md             ; 6 :  
  104.      MSR     CPSR_c,r1                  ; 6 : change SVC mode  
  105.      SUB     r13,r13,#FRAME_SIZE-FRAME_R4 ; 7 : make stack space   
  106.      STMIA   r13,{r4-r11}               ; 7 : save r4-r11  
  107.      LDMIA   r0,{r4-r9}                 ; 7 : r4-r9 IRQ stack   
  108.      BIC     r1,r1,#I_Bit               ; 8 :   
  109.      MSR     CPSR_c,r1                  ; 8 : enable int  
  110.      STMDB   r13!,{r4-r7}               ; 9 : save r4-r7 SVC  
  111.      STR     r2,[r13,#FRAME_PSR]        ; 9 : save PSR  
  112.      STR     r8,[r13,#FRAME_R12]        ; 9 : save r12  
  113.      STR     r9,[r13,#FRAME_PC]         ; 9 : save pc        
  114.      STR     r14,[r13,#FRAME_LR]        ; 9 : save lr  
  115.      ; <insert code here>  
  116.      LDMIA   r13!,{r0-r12,r14}          ; 11 : restore context  
  117.      MSR     SPSR_cxsf,r14              ; 11 : restore SPSR  
  118.      LDMIA   r13!,{r14,pc}^             ; 11 : return  
  119.   
  120.   
  121. read_RescheduleFlag  
  122.      ; <implement your own reschedule flag code here>  
  123.      MOV     r0,#0                      ; more processing   
  124.      MOV     pc,r14                     ; return  
  125.   
  126.      END  

代码的关键就是在中断后切换到SVC模式下,利用svc mode的stack来实现中断嵌套过程的备份以及恢复操作.从代码中可以看到,从R0到PC都在栈中有备份,这里我们叫栈帧.记得《深入理解计算机系统》一书在讲x86汇编的函数调用时也是栈帧的概念.这点上中断嵌套和函数调用有相似之处.有了这个栈帧,利用压栈出栈操作就一切ok了.


        刚看这个代码,对有个地方有疑问,就是觉得中断开早了:

     BIC     r1,r1,#I_Bit               ; 8 :
     MSR     CPSR_c,r1                  ; 8 : enable int
     STMDB   r13!,{r4-r7}               ; 9 : save r4-r7 SVC
     STR     r2,[r13,#FRAME_PSR]        ; 9 : save PSR
     STR     r8,[r13,#FRAME_R12]        ; 9 : save r12
     STR     r9,[r13,#FRAME_PC]         ; 9 : save pc     
     STR     r14,[r13,#FRAME_LR]        ; 9 : save lr

        觉得开中断的代码应该放在后面,这样才能保证svc mode下的stack frame不会被破坏.但在草稿纸上画一下irq和svc下的stack图,就发现堆栈操作并没有问题.可以假设刚开中断立马就有新的中断了,r4-r7 r8 r9都有在STMIA   r13,{r4-r11} 中保存到svc的stack中,LDMIA   r0,{r4-r9} 和STMDB   r13!,{r4-r7} 保证了最初的r0-r3在栈中,而LDMIA   r0,{r4-r9}和STR     r8,[r13,#FRAME_R12] 以及STR     r9,[r13,#FRAME_PC] 保证了R12和PC,保证正确返回.(这里的r9装的是r14_irq,所以pc就是r14_irq,这样就保证了从中断服务例程中返回).至于STR     r14,[r13,#FRAME_LR]中的r14是r14_svc,将其压入svc的stack中,中断例程用bl就不会出现错误了,在最后LDMIA   r13!,{r14,pc}^ 中r14得到恢复.而r2保存的是spsr,也就是svc模式的状态,一直不变,不用担心会被覆盖.

        最后,再看了一遍图,觉得r10和r11的帧可以省去,因为r4-r9是用来存atpcs的r0-r3,r12,r14,而r10和r11用不到.貌似可以省点空间和时间,具体的待会实验一下.

        下面给出实际的嵌套中断处理,利用r10来保存INTOFFSET的值,根据该值来判定是什么中断,从而做不同的处理.具体的效果是:代码会做流水灯的动作,Key1代表INT1,中断处理动作是4个灯全全亮然后全灭,Key4代表代表INT0,中断处理动作是第一个灯和第三个灯亮,然后第二个灯和第四个灯亮.

 
  1. /* 
  2. simple interruption 
  3. copyleft@dndxhej@gmail.com 
  4. */  
  5.   
  6. .equ    Maskmd, 0x1f                     @ processor mode mask  
  7. .equ    SVC32md,     0x13                     @ SVC mode  
  8. .equ    I_Bit,       0x80                     @ IRQ bit   
  9.   
  10. .equ    FRAME_R0,    0x00             
  11. .equ    FRAME_R1,    FRAME_R0+4  
  12. .equ    FRAME_R2,    FRAME_R1+4  
  13. .equ    FRAME_R3,    FRAME_R2+4  
  14. .equ    FRAME_R4,    FRAME_R3+4  
  15. .equ    FRAME_R5,    FRAME_R4+4  
  16. .equ    FRAME_R6,    FRAME_R5+4  
  17. .equ    FRAME_R7,    FRAME_R6+4  
  18. .equ    FRAME_R8,    FRAME_R7+4  
  19. .equ    FRAME_R9,    FRAME_R8+4  
  20. .equ    FRAME_R10,   FRAME_R9+4  
  21. .equ    FRAME_R11,   FRAME_R10+4  
  22. .equ    FRAME_R12,   FRAME_R11+4  
  23. .equ    FRAME_PSR,   FRAME_R12+4  
  24. .equ    FRAME_LR,    FRAME_PSR+4  
  25. .equ    FRAME_PC,    FRAME_LR+4  
  26. .equ    FRAME_SIZE,  FRAME_PC+4  
  27.   
  28.   
  29.   
  30. .equ   NOINT, 0xc0  
  31. .equ    WTCON,  0x53000000  
  32. .equ    GPBCON, 0x56000010      @led  
  33. .equ    GPBDAT, 0x56000014      @led  
  34. .equ   GPBUP,        0x56000018    @led  
  35. .equ    GPFCON, 0x56000050      @interrupt config  
  36. .equ    EINTMASK, 0x560000a4  
  37. .equ    EXTINT0,  0x56000088  
  38. .equ    EXTINT1,  0x5600008c  
  39. .equ    EXTINT2,  0x56000090  
  40. .equ    INTMSK,  0x4A000008  
  41. .equ   EINTPEND,     0x560000a8  
  42.   
  43. .equ   INTSUBMSK,    0X4A00001C  
  44.   
  45. .equ   SRCPND,   0X4A000000  
  46. .equ   INTPND,   0X4A000010  
  47.   
  48. .equ    INTOFFSET,  0x4A000014  
  49.   
  50. .global _start  
  51. _start:     b   reset  
  52.         ldr     pc, _undefined_instruction  
  53.         ldr     pc, _software_interrupt  
  54.         ldr pc, _prefetch_abort  
  55.         ldr pc, _data_abort  
  56.         ldr pc, _not_used  
  57.         @b  irq  
  58.         ldr     pc, _irq  
  59.         ldr     pc, _fiq  
  60.   
  61.   
  62.   
  63. _undefined_instruction:     .word undefined_instruction  
  64. _software_interrupt:        .word software_interrupt  
  65. _prefetch_abort:        .word prefetch_abort  
  66. _data_abort:            .word data_abort  
  67. _not_used:          .word not_used  
  68. _irq:               .word irq  
  69. _fiq:               .word fiq  
  70.   
  71. .balignl 16,0xdeadbeef  
  72.   
  73. reset:  
  74.   
  75.   
  76.     ldr     r3, =WTCON  
  77.     mov r4, #0x0                       
  78.     str r4, [r3]    @ disable watchdog      
  79.   
  80.     ldr r0, =GPBCON  
  81.     ldr r1, =0x15400  
  82.     str r1, [r0]  
  83.   
  84.     ldr r2, =GPBDAT  
  85.     ldr r1, =0x160  
  86.     str r1, [r2]  
  87.   
  88.     bl delay  
  89.   
  90.   
  91.     msr cpsr_c, #0xd2 @进入中断模式  
  92.     ldr sp, =0xc00 @中断模式的栈指针定义  
  93.   
  94.     msr cpsr_c, #0xd3 @进入svc模式  
  95.     ldr sp, =0xfff @设置svc模式的栈指针  
  96.   
  97. @--------------------------------------------  
  98.   
  99.     ldr r0, =GPBUP  
  100.     ldr r1, =0x03f0    
  101.     str r1, [r0]        
  102.      
  103.     ldr r0, =GPFCON  
  104.     ldr r1, =0x2ea@0x2      
  105.     str r1, [r0]    
  106.   
  107.     ldr r0, =EXTINT0  
  108.     @ldr    r1, =0x8f888@0x0@0x8f888      @~(7|(7<<4)|(7<<8)|(7<<16))  
  109.     ldr r1, =0xafaaa  
  110.     str r1, [r0]    
  111.   
  112.     ldr r0, =EINTPEND  
  113.     ldr r1, =0xf0@0b10000  
  114.     str r1, [r0]    
  115.   
  116.     ldr r0, =EINTMASK  
  117.     ldr r1, =0x00@0b00000  
  118.     str r1, [r0]    
  119.   
  120.   
  121.   
  122.     ldr r0, =SRCPND  
  123.     ldr r1, =0xff@0x1@0b11111  
  124.     str r1, [r0]    
  125.   
  126.     ldr r0, =INTPND  
  127.     ldr r1, =0xff@0x1@0b11111  
  128.     str r1, [r0]    
  129.   
  130.     ldr r0, =INTMSK  
  131.     ldr r1, =0xffffff00@0b00000  
  132.     str r1, [r0]    
  133.   
  134.     MRS r1, cpsr  
  135.     BIC r1, r1, #0x80  
  136.     MSR cpsr_c, r1  
  137.   
  138.   
  139.     bl     main  
  140.   
  141. irq:  
  142.      sub     r14,r14,#4                 @ 2 :  
  143.      stmdb   sp!,{r0-r3,r12,r14}       @ 2 : save context  
  144.      @ <insert code here>  
  145.      @BL      read_RescheduleFlag        @ 3 : more processing  
  146.      @CMP     r0,#0                      @ 3 : if processing?  
  147.      @LDMNEIA sp!,{r0-r3,r12,pc}^       @ 4 :   then return   
  148. @@@@@@@@@@@@@@@@  
  149.     ldr r10,=INTOFFSET           @用r10保存中断的offset  
  150.     ldr r10,[r10]  
  151.   
  152.          ldr r0,=EINTPEND  
  153.          ldr r1,=0xf0  
  154.          str r1,[r0]   
  155.   
  156.     ldr r0, =SRCPND  
  157.     ldr r1, =0x3f@0b11111  
  158.     str r1, [r0]    
  159.   
  160.   
  161.   
  162.     ldr r0, =INTPND  
  163.     ldr r1, =0x3f@0b11111  
  164.     str r1, [r0]    
  165. @@@@@@@@@@@@@@  
  166.      mrs     r2,SPSR                    @ 5 : copy SPSR_irq  
  167.      mov     r0,sp                     @ 5 : copy sp_irq  
  168.      add     sp,sp,#6*4               @ 5 : reset stack  
  169.      mrs     r1,CPSR                    @ 6 : copy CPSR  
  170.      bic     r1,r1,#Maskmd              @ 6 :  
  171.      orr     r1,r1,#SVC32md             @ 6 :  
  172.      msr     CPSR_c,r1                  @ 6 : change SVC mode  
  173.      sub     sp,sp,#FRAME_SIZE-FRAME_R4 @ 7 : make stack space   
  174.      stmia   sp,{r4-r11}               @ 7 : save r4-r11  
  175.      ldmia   r0,{r4-r9}                 @ 7 : r4-r9 IRQ stack   
  176.   
  177.   
  178.      bic     r1,r1,#I_Bit               @ 8 :   
  179.      msr     CPSR_c,r1                  @ 8 : enable int  
  180.      stmdb   sp!,{r4-r7}               @ 9 : save r4-r7 SVC  
  181.      str     r2,[sp,#FRAME_PSR]        @ 9 : save PSR  
  182.      str     r8,[sp,#FRAME_R12]        @ 9 : save r12  
  183.      str     r9,[sp,#FRAME_PC]         @ 9 : save pc        
  184.      str     r14,[sp,#FRAME_LR]        @ 9 : save lr  
  185.   
  186.      @ <insert code here>  
  187. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  
  188.       
  189.     cmp r10,#0x0  
  190.     bleq    blink1  
  191.   
  192.   
  193.     cmp r10,#0x1  
  194.     bleq    blink3  
  195.   
  196.   
  197.   
  198. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  
  199.      LDMIA   sp!,{r0-r12,r14}          @ 11 : restore context  
  200.      MSR     SPSR_cxsf,r14              @ 11 : restore SPSR  
  201.      LDMIA   sp!,{r14,pc}^             @ 11 : return  
  202.   
  203.    
  204.   
  205. delay:  
  206.       
  207.     ldr r3,=0xffff  
  208.   
  209. delay1:  
  210.     sub r3,r3,#1  
  211.   
  212.     cmp r3,#0x0  
  213.   
  214.     bne delay1  
  215.   
  216.     mov pc,lr  
  217.   
  218. blink1:  
  219.     ldr r0, =GPBDAT  
  220.     ldr r1, =0x000  
  221.     str r1, [r0]  
  222.       
  223.     ldr r3,=0xffff  
  224.   
  225. delay2:  
  226.     sub r3,r3,#1  
  227.   
  228.     cmp r3,#0x0  
  229.   
  230.     bne delay2  
  231.   
  232.   
  233.     ldr r0, =GPBDAT  
  234.     ldr r1, =0x1f0  
  235.     str r1, [r0]  
  236.       
  237.     ldr r3,=0xffff  
  238.   
  239. delay3:  
  240.     sub r3,r3,#1  
  241.   
  242.     cmp r3,#0x0  
  243.   
  244.     bne delay3  
  245.   
  246.     mov pc,lr  
  247.   
  248. blink2:  
  249.     ldr r0, =GPBDAT  
  250.     ldr r1, =0x140  
  251.     str r1, [r0]  
  252.       
  253.     ldr r3,=0xffff  
  254.   
  255. delay12:  
  256.     sub r3,r3,#1  
  257.   
  258.     cmp r3,#0x0  
  259.   
  260.     bne delay12  
  261.   
  262.     ldr r0, =GPBDAT  
  263.     ldr r1, =0xa0  
  264.     str r1, [r0]  
  265.       
  266.     ldr r3,=0xffff  
  267.   
  268. delay13:  
  269.     sub r3,r3,#1  
  270.   
  271.     cmp r3,#0x0  
  272.   
  273.     bne delay13  
  274.     mov pc,lr  
  275.   
  276. blink3:  
  277.     ldr r0, =GPBDAT  
  278.     ldr r1, =0x0a0  
  279.     str r1, [r0]  
  280.   
  281.     stmfd   sp!,{lr}  
  282.   
  283.     bl delay  
  284.   
  285.     ldr r0, =GPBDAT  
  286.     ldr r1, =0x140  
  287.     str r1, [r0]  
  288.       
  289.     bl delay  
  290.   
  291.     ldmfd   sp!,{lr}  
  292.     mov pc,lr  
  293.   
  294.   
  295. main:  
  296. ledloop:  
  297.   
  298.     ldr r1,=0x1c0  
  299.     str r1,[r2]  
  300.     bl delay  
  301.   
  302.     ldr r1,=0x1a0  
  303.     str r1,[r2]  
  304.     bl delay  
  305.   
  306.     ldr r1,=0x160  
  307.     str r1,[r2]  
  308.     bl delay  
  309.   
  310.     ldr r1,=0x0e0  
  311.     str r1,[r2]  
  312.     bl delay  
  313.   
  314.     b ledloop  
  315.   
  316.   
  317.   
  318.   
  319. undefined_instruction:  
  320.             nop  
  321. software_interrupt:  
  322.             nop  
  323. prefetch_abort:   
  324.             nop  
  325. data_abort:  
  326.             nop  
  327. not_used:  
  328.             nop  
  329. fiq:  
  330.             nop  

代码比较繁琐,有几点值得注意:在嵌套中断处理中,压栈后先保存INTOFFSET的值,再清中断(SRCPND和INTPND).因为SRCPND和INTPND清除后INTOFFSET就自动清除了,所以要先保存.在中断服务程序中,是可以用bl跳转到各自的中断服务程序的,比如blne    blink1和blne    blink3,值得对比的blink1和blink3,他们的不同在于blink1自己用代码做了延时,而blink3是调用bl delay做的延时,那么这个时候要注意的就是lr的push和pop操作,不然lr就被覆盖了,程序不能正确返回了.

注意了以上两点,程序上达到了嵌套处理的效果.因为采用的是下降边沿触发,而按键没有防抖处理,有时候单按一个键就有嵌套中断了.最后总结一下这种处理的优缺点:优点是在为一个中断处理服务完成前允许其它中断,以缩短中断延迟;而缺点是不处理中断的优先级,因此低优先级的中断会阻塞高优先级的中断.

linux
【内容导航】
第1页:开篇 第2页:汇编编译链接与运行
第3页:ARM处理器的基本原则 第4页:中断汇编之非嵌套中断处理
第5页:中断汇编之嵌套中断处理 第6页:s3c2440的时钟控制
第7页:s3c2440的串口控制 第8页:s3c2440的watchdog
第9页:s3c2440的PWM 第10页:s3c2440的RTC
第11页:小结 第12页:arm汇编指令的B真的那么简单吗?
第13页:GNU ARM汇编下的linker script 第14页:GNU ARM汇编下做任务调度
第15页:Linux下的printascii 第16页:bootloader与kernel之间的commandline的传递
第17页:u-boot的makefile和mkconfig解读 第18页:u-boot-采用nand_spl方式的启动方法
第19页:u-boot-nand-spl启动过程分析 第20页:总结
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款