■IRQ 분석


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    .equ _ISR_STARTADDRESS,        0x33ffff00
 
_start:
 
    /* ResetHandler가 처음부터 나오는 것이 아니라 
     * vector 주소 영역에는 reset vector가 존재해야 한다
     * exception이 발생하면 ARM은 하드웨어적으로 다음 주소로 분기된다
     */
    b    ResetHandler
    b    HandlerUndef            /* handler for Undefined mode */
    b    HandlerSWI            /* handler for SWI interrupt */
    b    HandlerPabort            /* handler for PAbort */
    b    HandlerDabort            /* handler for DAbort */
    b    .                        /* reserved */
    b    HandlerIRQ                /* handler for IRQ interrupt */
    b    HandlerFIQ                /* handler for FIQ interrupt */
 
    .ltorg
HANDLER HandlerFIQ, HandleFIQ
HANDLER HandlerIRQ, HandleIRQ
HANDLER HandlerUndef, HandleUndef
HANDLER HandlerSWI, HandleSWI
HANDLER HandlerDabort, HandleDabort
HANDLER HandlerPabort, HandlePabort
 
 
    /* 여기서 IRQ가 발생할때 위에서 만든 
     * IsrIRQ 루틴으로 분기하기 위한 ISR_VECTOR 설정을 한다 
     */
    /* Setup IRQ handler */
    ldr    r0,=HandleIRQ  
    ldr    r1,=IsrIRQ            
    str    r1,[r0]
 
 
// check  INTOFFSET1
 chk_off1:
        ldr     r9,=INTOFFSET1
        ldr     r9,[r9]
        cmp r9,#0
      beq   chk_off2
        ldr     r8,=HandleEINT0
        add     r8,r8,r9,lsl #2
        b end_off
 
 // check  INTOFFSET2
 chk_off2:
        ldr     r9,=INTOFFSET2
        ldr     r9,[r9]
        cmp r9,#0
      beq   abt_return
        ldr     r8,=Handle2D
        add     r8,r8,r9,lsl #2
 
end_off: // generic interrupt
        ldr     r8,[r8]
        str     r8,[sp,#8]
        ldmfd   sp!,{r8-r9,pc} 
 
abt_return: // no interrupt
     sub lr,lr,#4
        str   lr,[sp,#8]
        ldmfd   sp!,{r8-r9,pc}^
 
    /* function initializing stacks */
cs



■그림으로 보는 IRQ


SWI, HandlerLabel 매크로 동작


#분석


1.SWI 명령어를 만나면 0x08번지로 이동.

1
HandleSWI:            .long   (_ISR_STARTADDRESS + 0x8)    // interrupt 함수주소를 획득하여 분기한다.
cs

1
2
3
4
5
6
7
8
9
    _start:
 
    /* ResetHandler가 처음부터 나오는 것이 아니라 
     * vector 주소 영역에는 reset vector가 존재해야 한다
     * exception이 발생하면 ARM은 하드웨어적으로 다음 주소로 분기된다
     */
    b    ResetHandler
    b    HandlerUndef            /* handler for Undefined mode */
    b    HandlerSWI            /* handler for SWI interrupt */
cs


=>    b    HandlerSWI로 이동, 이때 HANDLER 매크로가 등록이 되어있고 매크로를 수행.


1
HANDLER HandlerSWI, HandleSWI
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    .macro HANDLER, HandlerLabel, HandleLabel
\HandlerLabel:
    sub        sp,sp,#4        /* decrement sp(to store jump address) */
    stmfd    sp!,{r0}            /* PUSH the work register to stack(lr doesn`t push because */ 
                               /* it return to original address) */
    ldr        r0,=\HandleLabel    /* load the address of HandleXXX to r0 */
    ldr        r0,[r0]                 /* load the contents(service routine start address) of HandleXXX */
        
 
    str        r0,[sp,#4]          /* store the contents(ISR) of HandleXXX to stack */
 
    ldmfd    sp!,{r0,pc}         /* POP the work register and pc(jump to ISR) */
    .endm
 
    .text
    .globl_start
cs


=>매크로를 수행하게 되면 pc에 저장된 주소로 jump하게 된다.


1
2
3
4
5
6
7
8
9
extern unsigned int  HandleSWI;
 
HandleSWI    = (unsigned)SWI_Handler;
 
void SWI_Handler(void)
{
    Uart_Printf("SWI exception.\n");
    for(;;);
}
cs



■그림으로 보는 동작 과정




 ■ARM Operaing Mode

 

MOV R0, #0x104 => 1 0000 0100

MOV R0, #0x102 => 1 0000 0010

 

#operand 2 4bit#rot , 8bitImmediate으로 구성되어 있습니다.

 

◆0x104를 32bit로 표현하면

 

0x104 : 0000 0000 0000 0000 0000 0001 0000 0100

 

0100 0001을 오른쪽으로 30회전하면 0x104를 표현할 수 있습니다.

 

(0회전) 0000 0000 0000 0000 0000 0000 0100 0001

(1회전) 1000 0000 0000 0000 0000 0000 0010 0000

(2회전) 0100 0000 0000 0000 0000 0000 0001 0000

(3회전) 0010 0000 0000 0000 0000 0000 0000 1000

 

                                ....

 

(30회전)0000 0000 0000 0000 0000 0001 0000 0100

 

 

8-bit Immediate 상수값을 #rot2배한 만큼 오른쪽으로 로테이션(ROR)을 하는데

15 * 2 =30 으로 표현이 가능합니다.


◆0x102를 32bit로 표현하면


0x102 : 0000 0000 0000 0000 0000 0001 0000 0010

 

1000 0001을 오른쪽으로 31회전하면 0x102를 표현할 수 있습니다.

 

(0회전) 0000 0000 0000 0000 0000 0000 1000 0001

(1회전) 1000 0000 0000 0000 0000 0000 0100 0000

(2회전) 0100 0000 0000 0000 0000 0000 0010 0000

(3회전) 0010 0000 0000 0000 0000 0000 0001 0000

                                    ....

 

(31회전)0000 0000 0000 0000 0000 0001 0000 0010

 

여기서 ?? * 2 =31으로 표현이 가능해야 하는데 31을 표현할 수 없어서

0x102는 값을 만들 수가 없습니다.

 

즉, 회전하는 총 횟수가 2의 배수여야 합니다.

 

 

 

0xfc000003를 32bit로 표현하면 


0xfc000003: 1111 1100 0000 0000 0000 0000 0000 0011

 

 

8-bit Immediate값을 0xFF로 표현할 수 있습니다.

6회전을 하면 가능합니다. => #rot -> #0x3

 

(0회전) 0000 0000 0000 0000 0000 0000 1111 1111

(1회전) 1000 0000 0000 0000 0000 0000 0111 1111

(2회전) 1100 0000 0000 0000 0000 0000 0011 1111

(3회전) 1110 0000 0000 0000 0000 0000 0001 1111

(4회전) 1111 0000 0000 0000 0000 0000 0000 1111

(5회전) 1111 1000 0000 0000 0000 0000 0000 0111

(6회전) 1111 1100 0000 0000 0000 0000 0000 0011

 

#rot * 2 = 6, 8-bit Immediate = 0xFF

 

, ROR의 회전수가 2의 배수여야하고 8-bit Immediate(로테이션 할 값)8bit로 제한되어있어서 8bit를 초과하면 안된다는 조건이 있습니다.

 

 

 

 

 

■Memcpy_Single

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#if EXAMPLE == 11
void MemFill(unsigned long ptr,unsigned long pattern,int size)
{
    long *= ptr;
    while(size--)
    {
        *s++ = pattern;
    }
 
}
void MemDump(unsigned long ptr,int size)
{
    long *= ptr;
    while(size--)
    {
        Uart_Printf("[%x]  ",*s++);
        if(size%4==0)
        Uart_Printf("\n");
    }    
}
 
 
void Main(void)
{    
unsigned char ch;
 
    unsigned long src = 0x33000000;
    unsigned long dst = 0x33100000;
    int size = 12;
    unsigned long pattern;
    MemFill(src,0x00000000,size);
    MemFill(dst,0x00000000,size);
    Uart_Printf("Start Memory copy test\n");
 
    pattern = 0x5555aaaa;
    Uart_Printf("\nFill pattern [0x%08x] to [0x%08x]\n",pattern,src);
    MemFill(src,pattern,size);    
    
    Uart_Printf("Dump Memory from [0x33000000] to [0x33000030]\n");
    MemDump(src,size);
    Uart_Printf("\nCopy from [0x%08x] to [0x%08x] by use LDR/STR\n",src,dst);
 
    MEMCPY_SINGLE(dst,src,size);
    Uart_Printf("Dump Memory from [0x33100000] to [0x33100030]\n");
    MemDump(dst,size);
            
}
# endif  
 
 
/******************************ARM*************************/
    .globl MEMCPY_SINGLE
 
MEMCPY_SINGLE:
    LDR    r3,[r1],#4
    STR    r3,[r0]
    add    r0,r0,#4
    subs r2,r2,#1
bne    MEMCPY_SINGLE
    mov pc,lr
/******************************ARM*************************/
 
cs

#결과


■Memcpy_Single



#LDM/STM의 어드레스 저장방식은 4가지가 있다. 

(Increment Before, Increment After, Decrement Before, Decrement After)

프로세스마다 방식이 다르며 참고로 ARM에서는 Stack 동작에서 Full Descending방식을 쓴다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
MEMCPY_MULTIPLE_IA:
    LDMIA    r1!,{r3-r5}
    STMIA    r0!,{r3-r5}        
    subs r2,r2,#3
bne    MEMCPY_MULTIPLE
    mov pc,lr
 
MEMCPY_MULTIPLE_IB:
    SUB        r1,r1,#0x4
    SUB     r0,r0,#0x4
kk:
    LDMIB    r1!,{r3-r5}
    STMIB    r0!,{r3-r5}        
    subs r2,r2,#3
bne    kk
    mov pc,lr
 
MEMCPY_MULTIPLE_DA:
    add        r1,r1,#0x2c
    add         r0,r0,#0x2c
kk:
    LDMDA    r1!,{r3-r5}
    STMDA    r0!,{r3-r5}        
    subs r2,r2,#3
bne    kk
    mov pc,lr
 
MEMCPY_MULTIPLE_DB:
    add        r1,r1,#0x30
    add         r0,r0,#0x30
kk:
    LDMDB    r1!,{r3-r5}
    STMDB    r0!,{r3-r5}        
    subs r2,r2,#3
bne    kk
    mov pc,lr
cs





■두더지 게임


#LED가 켜진 위치의 키보드 버튼을 누르면 LED가 꺼지고 랜덤으로 다른 LED가 켜진다.

  UTRSTAT1과URXH1을 이용하여 LOOP도는 중에 키보드 입력을 받아 값을 처리한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
P1:
mov r4,r0
ldr     r0,=GPGCON
    ldr     r1,=0x5500
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0xf0
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0xe0
    str    r1,[r0]
b    My_Delay
   
P2:
    mov r4,r0
ldr     r0,=GPGCON
    ldr     r1,=0x5500
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0xf0
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0xd0
    str    r1,[r0]
b    My_Delay
P3:
    mov r4,r0
ldr     r0,=GPGCON
    ldr     r1,=0x5500
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0xf0
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0xb0
    str    r1,[r0]
b    My_Delay
P4:
    mov r4,r0
ldr     r0,=GPGCON
    ldr     r1,=0x5500
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0xf0
    str    r1,[r0]
 
    ldr    r0,=GPGDAT
    ldr    r1,=0x70
    str    r1,[r0]
b    My_Delay
 
 
 
My_Delay:
    ldr r2,=0
    ldr r3,=2000000
My_Delay2:    
    add r2,r2,#1
    cmp r2,r3
    moveq r0,#0
    moveq pc,lr
    
    ldr r0,=0x50004010        //UTRSTAT1
    ldr r1,[r0]
    and r1,r1,#0x1
    cmp r1,#0x1
    ldreq    r1,=0x50004024    //URXH1
    ldr r0,[r1]
    cmp r0,r4
bne    My_Delay2
    mov pc,lr
cs


■환경 설정

(Ubuntu)


공유파일에 03-06_Ch3_Basic_Devices.zip 추가


#unzip 03-06_Ch3_Basic_Devices


#cd 03-06_Ch3_Basic_Devices/SOURCE/



#vi Makefile


기존의 TOOLPATH 주석처리

TOOLPATH = /root/arm-2011.03 추가 ==>make 되는지 확인



#vi Main.c


16번줄 ->#define EXAMPLE 320 수정



85번줄 함수에서


int a,b,result;


a=10; b=20; 


result = CONDITIONAL_EXECUTE(a,b);

Uart_Printf("\n result=%d",result);

Uart_Printf("\n");


추가


#vi s3c2450_startup.S


93번줄(reset handler 아래)

.globl CONDITIONAL_EXECUTE 추가


CONDITIONAL_EXECUTE :

cmp r0,r1

movLT r0,#1

movGt r0,#2

movEQ r0,#3

mov pc,lr


추가


#make clean

#make


#cp MDS2450.bin /tftpboot




#LED 켜기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
.globl LED_ON
.globl LOOP
 
 
 
LED_ON:
 
    ldr     r0,=GPGCON
 
    ldr     r1,=0x5500
 
    str    r1,[r0]
 
 
 
    ldr    r0,=GPGDAT
 
    ldr    r1,=0xf0
 
    str    r1,[r0]
 
 
 
    ldr    r0,=GPGDAT
 
    ldr    r1,=0xe0
 
    str    r1,[r0]
 
bl LOOP
 
ldr    r0,=GPGDAT
 
    ldr    r1,=0xd0
 
    str    r1,[r0]
 
bl LOOP
 
ldr    r0,=GPGDAT
 
    ldr    r1,=0xb0
 
    str    r1,[r0]
 
bl LOOP
 
ldr    r0,=GPGDAT
 
    ldr    r1,=0x70
 
    str    r1,[r0]
 
bl LOOP
 
 
 
b LED_ON
 
 
 
 
 
LOOP:
 
    ldr r3,=0
 
    ldr r4,=5000000
 
LOOP1:    
 
    add r3,r3,#1
 
    cmp r3,r4
 
bne    LOOP1
cs




■ARM 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
int main(void)
{
int a;
int b;
int c;
int i;
int result;
int start,end,sum,max;
 
    HOW_TO_RETURN(); 
 
 
 
#if 0    
    a=9;b=11/* a < b condition */
    result = CONDITIONAL_EXECUTE(a,b);
 
    a=11;b=10/* a < b condition */
    result = CONDITIONAL_EXECUTE(a,b);
 
    a=10;b=10/* a < b condition */
    result = CONDITIONAL_EXECUTE(a,b);
#endif
 
 
#if 0
    a=11;b=22;c=30;
    result = DATA_PROCESS1(a,b,c);
#endif
 
#if 0
    a=0x10; b=0x33;
    result = DATA_PROCESS2(a,b);
#endif
 
#if 0
    start =1;end =5;
    sum = SUM_OF_DEC(start,end);
#endif
 
 
#if 1
    start =0;end =1;
    sum = Fibonacci(start,end);
#endif
 
 
return i;
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 
                        /* 프로그램 시작 */
    .text              /* 프로그램 정의 */
    .arm               /* ARM 프로세서 */
    .global HOW_TO_RETURN
    .global CONDITIONAL_EXECUTE
    .global DATA_PROCESS1
    .global DATA_PROCESS2
    .global SUM_OF_DEC
    .global Fibonacci
 
 
RESET:  B      MAIN        /* MAIN으로 점프 */
        /* 메인 프로그램 */
        .org    0x100
MAIN:   MOV     R0,#2          /* R0 <- 2 */
        MOV     R1,R0          /* R1 <- R0 */
    b main
 
 
HOW_TO_RETURN:
   mov r0,#0x00000010
   mov pc,lr
 
CONDITIONAL_EXECUTE:
    cmp r0,r1
    movgt r0,#1    
    movlt r0,#2
    moveq r0,#3    
    mov pc,lr
DATA_PROCESS1:
    add r0,r0,r1
    sub r0,r0,r2
    mov pc,lr 
DATA_PROCESS2:
    and r3,r1,#15
    orr r3,r3,r0,LSL#2
    mov r3,r0
    mov pc,lr 
 
SUM_OF_DEC:
    mov r3,#0
FOR:
    add r3,r3,r0
    add r0,r0,#1
    cmp r0,r1
    ble FOR
    mov r0,r3
    mov pc,lr
 
Fibonacci:
 
Fibonacci1:
    add r2,r0,r1
    mov r0,r1
    mov r1,r2
b Fibonacci1
    
    mov pc,lr
 
.end
cs




#피보나치 결과






■ARM Operaing Mode



#Mode bits

-ARM의 7가지의 동작모드


#Exception Vector Table 




.text "지금부터 명령어를 실행할것이다" 라는 지시어 (지시어는 용량을 차지 하지 않는다)
* RESET,MAIN ..등등 을 label이라고 한다.

* swi가면 무조건 Supervisor 모드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
         /* 프로그램 시작 */
        .text              /* 프로그램 정의 */    
        .arm               /* ARM 프로세서 */    
 
RESET:  B    MAIN        /* MAIN으로 점프 */
 
        B    Undefined_Instruction 
        B    Software_Interrupt
        B    Prefetch_Abort
        B    Data_Abort
        B    Reserved
        B    IRQ
        B    FIQ
 
    /* 메인 프로그램 */
        .org    0x100
MAIN:   MOV     R0,#2          /* R0 &lt;- 2 */
        MOV     R1,R0          /* R1 &lt;- R0 */
                    
        mov     r0, #3  /* fiq */
        swi     0x08    /*cpsr_c = r0*/
Software_Interrupt :
    mov     r0, #0x00000013  
    msr     cpsr_c, r0
Undefined_Instruction : 
    mov     r0, #0x0000001b  
    msr     cpsr_c, r0
Prefetch_Abort : 
    mov     r0, #0x00000017  
    msr     cpsr_c, r0
Data_Abort : 
    mov     r0, #0x00000017  
    msr     cpsr_c, r0
Reserved :
IRQ : 
    mov     r0, #0x00000012  
    msr     cpsr_c, r0
FIQ : 
    mov     r0, #0x00000011  
    msr     cpsr_c, r0
    .end
cs

#test#
swi 명령어를 통해서 디버깅을 하도록 코드를 만들었습니다.
각각의 mode bits를 PSR의 control bits에 넣었을 때 mode가 변경되는 것을 확인할 수 있습니다.


+ Recent posts