[컴퓨터구조] Ch7-1. Running Keil Tools

김규원·2024년 6월 7일
post-thumbnail

▶ Running Keil Tools

Working with an ARM7TDMI

Creating Application Code

Source file

GLOBAL Reset_Handler
AREA Prog1, CODE, READONLY
ENTRY
ARM
Reset_Handler
MOV r0, #0x11      ; 초기 값을 로드합니다
LSL r1, r0, #1     ; 1비트 왼쪽으로 시프트합니다
LSL r2, r1, #1     ; 1비트 왼쪽으로 시프트합니다
stop
B stop             ; 프로그램을 멈춥니다
END
  1. GLOBAL Reset_Handler: Reset_Handler 라벨을 전역으로 정의
  2. AREA Prog1, CODE, READONLY: 읽기 전용 코드 영역을 정의.
    영역 이름: "Prog1"
  3. ENTRY: 프로그램의 진입점을 표시.
  4. ARM: ARM 명령어 시퀀스의 시작을 알림.
  5. Reset_Handler: 리셋 핸들러의 시작을 나타내는 라벨.
  6. MOV r0, #0x11: 레지스터 r0에 0x11 값을 로드.
  7. LSL r1, r0, #1: 레지스터 r0의 값을 1비트 왼쪽으로 시프트하고, 결과를 레지스터 r1에 저장.
  8. LSL r2, r1, #1: 레지스터 r1의 값을 1비트 왼쪽으로 시프트하고, 결과를 레지스터 r2에 저장.
  9. stop: 이 라벨은 프로그램을 멈추는 지점을 표시.
  10. B stop: 프로그램 실행을 멈추고, stop 라벨로 무한 루프를 형성.
  11. END: 소스 파일의 끝을 나타냄.

따라서, AREA 지시어가 Prog1이라는 코드 영역을 정의하고, 이 영역이 읽기 전용(READONLY)이므로, 그 안에 포함된 모든 명령어는 읽기 전용 코드 영역에 속하게 됨.

Building the project and Running code

Working with a Cortex-M4

Creating Application Code(1)

  1. 프로젝트 창에서 "Source Group 1" 아이콘 옆에 있는 + 기호를 클릭.
  2. Startup.s 이름을 두 번 클릭하여 해당 파일을 엶.
  3. Reset_Handler와 NMI_Handler 레이블 사이의 코드를 삭제.
  4. Reset_Handler 레이블 뒤에 "ENTRY" 지시어를 추가.
  5. 스택 및 힙 메모리 위치를 처리하는 코드를 주석 처리합. 현재 이러한 코드가 필요하지 않기 때문.

Creating Application Code (2)

; Reset Handler
	EXPORT Reset_Handler ; Reset_Handler를 외부로 내보내도록 설정
Reset_Handler ; Reset_Handler 레이블
	ENTRY ; 이 프로그램의 진입점
	MOV r6, #10 ; 레지스터 r6에 10을 로드
	MOV r7, #1 ; 레지스터 r7에 1을 로드. n의 초기값을 설정
loop ; 루프 시작
	CMP r6, #0 ; r6와 0을 비교
	MULGT r7, r6, r7 ; 만약 r6가 양수라면 r7에 r6 * r7의 결과를 저장
	SUBGT r6, r6, #1 ; 만약 r6가 양수라면 r6에서 1을 뺍니다. (n을 감소시캄.)
	BGT loop ; r6가 0이 아니라면 loop 레이블로 분기
stop B stop  ; 프로그램을 중단하는 레이블

Creating Application Code (3)

; User Initial Stack & Heap
; 	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
; 	LDR R1, =(Stack_Mem + Stack_Size)
; 	LDR R2, = (Heap_Mem + Heap_Size)
; 	LDR R3, = Stack_Mem
; 	BX LR
; 	ALIGN
; 	ENDIF
  • __MICROLIB가 정의되어 있으면 __initial_sp, __heap_base, __heap_limit을 외부로 내보내도록 설정
  • 그렇지 않은 경우, __use_two_region_memory를 가져와서 __user_initial_stackheap을 외부로 내보냄.
  • 현재 코드는 주석 처리되어 있으므로 이 코드 블록은 현재 사용되지 않음.

만약 주석이 없다면...

  • LDR R0, =Heap_Mem
    : Heap_Mem 주소를 로드하여 레지스터 R0에 저장합니다.
  • LDR R1, =(Stack_Mem + Stack_Size)
    : Stack_Mem과 Stack_Size를 합한 주소를 로드하여 레지스터 R1에 저장합니다.
  • LDR R2, =(Heap_Mem + Heap_Size): Heap_Mem과 Heap_Size를 합한 주소를 로드하여 레지스터 R2에 저장합니다.
  • LDR R3, =Stack_Mem
    : Stack_Mem 주소를 로드하여 레지스터 R3에 저장합니다.
  • BX LR:
    서브루틴에서 복귀할 위치를 레지스터 LR에 저장한 후 서브루틴을 종료합니다.
  • ALIGN
    : 다음 명령어를 정렬합니다.
  • ENDIF
    : 조건부 컴파일 지시어를 마칩니다. 하지만 주어진 코드에서 이전에 IF 조건문이 주어지지 않았으므로 이것은 현재 사용되지 않는 코드

Building the project and Running code

▶ 보충: Running Arm Keil Tools

  • 코드는 ARM7TDMI의 0x00000000 주소에서 시작

  • 이 주소는 보통 예외 벡터 테이블(exception
    vector table)이 있는 곳

  • 그렇기에 예외 처리가 필요하지 않으면 그 곳에 코드를 넣을 수 있음

  • 툴은 일반적으로 디폴트 리셋 핸들러(reset handler)가 벡터 테이블에 있을 것으로 예상하지만 지금은 이를 사용하지 않음. 따라서 툴이 프로그램을 리셋 핸들러로 믿도록 프로그램을 만듦.

  • Cortex-M4용 코드 작성도 동일한 방식. C 코드를 컴파일할 때 만드는 예외 처리기(exception handler)와
    어셈블리 코드는 제외

  • startup.s 코드 포함 여부는 초기화 코드의 유무라고 볼 수 있음
    : 우리는 작은 어셈블리 프로그램을 만들고 있으므로 초기화 코드가 따로 필요 없음.

애플리케이션 코드 생성

  • MDK 최신 버전은 reset handler를 필요로 하며 보통은 startup 파일에 포함
  • 그러나 우리는 startup.s파일을 사용하지 않고 있기에 사용자의 어셈블리 코드를 reset handler로 표기하고 이를 전역으로 선언
    : 이를 위해, 코드의 첫 번째 줄에 GLOBAL 지시어를 사용
    : AREA로 시작하는 코드 블록을 reset (혹은 Reset, 대소문자 구분하지 않음)으로 명명
  • ENTRY 지시어 다음에는 Reset_Handler 라벨이 코드의 최 상단에 위치해야 함.

디버깅

  • 툴 바의 Step Into 버튼이나 Debug 메뉴에서 Step을 선택해서 single-stepping을 실행 가능
  • 이때 레지스터 파일의 내용이 바뀌는 것을 볼 수 있음.
  • 주소를 타이핑해서 원하는 위치의 메모리 내용을 볼 수 있기도 함.

Cortex-M4 프로젝트 생성과 디바이스 선택

  • Cortex-M4에서는 초기화 코드를 사용해서 예제를 실행할 수 있기 때문에 Yes를 선택

애플리케이션 코드 생성

  • Startup.s 파일을 수정해서 사용
  1. Reset_Handler와 NMI_Handler 라벨 사이의 코드를 삭제하고 사용자 코드를 추가
  2. Reset_Handler 라벨 바로 다음에 ENTRY 지시어를 추가
  • 당장 필요하지 않은 스택과 힙 메모리 위치를 처리하기 위한 섹션의 코드를 주석 처리
  • 각 줄의 시작 부분에 세미콜론을 추가
; User Initial Stack & Heap
; 	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
; 	LDR R1, =(Stack_Mem + Stack_Size)
; 	LDR R2, = (Heap_Mem + Heap_Size)
; 	LDR R3, = Stack_Mem
; 	BX LR
; 	ALIGN
; 	ENDIF

프로젝트 빌드와 코드 실행

profile
행복한 하루 보내세요

0개의 댓글