Assembly 2 C language

Seungyun Lee·2026년 3월 17일

RTOS

목록 보기
11/14
;This program shows that the system uses PC to return from interrupt not LR
;since LR's value is 0xFFFFFFF9
AREA Block1, DATA, READWRITE, ALIGN=2
cnt DCD 0x0102
AREA Ex1, CODE, READONLY, ALIGN=2

NVIC_PRI17_R         EQU 0xE000E444
NVIC_PRI7_R          EQU 0xE000E41C
NVIC_EN0_R           EQU 0xE000E100
NVIC_EN1_R           EQU 0xE000E104
GPIO_PORTF_LOCK_R    EQU 0x40025520
GPIO_PORTF_CR_R      EQU 0x40025524
GPIO_PORTF_AMSEL_R   EQU 0x40025528
GPIO_PORTF_PCTL_R    EQU 0x4002552C
GPIO_LOCK_KEY        EQU 0x4C4F434B
GPIO_PORTF_DATA_R    EQU 0x400253FC
GPIO_PORTF_DIR_R     EQU 0x40025400
GPIO_PORTF_AFSEL_R   EQU 0x40025420
GPIO_PORTF_PUR_R     EQU 0x40025510
GPIO_PORTF_DEN_R     EQU 0x4002551C
GPIO_PORTF_IBE_R     EQU 0x40025408
GPIO_PORTF_IEV_R     EQU 0x4002540C
GPIO_PORTF_IM_R      EQU 0x40025410
GPIO_PORTF_RIS_R     EQU 0x40025414
GPIO_PORTF_ICR_R     EQU 0x4002541C
GPIO_PORTF_IS_R      EQU 0x40025404
DELAY EQU 8000000 ; delay 0.5sec (=8000,000*1/16MHz)

SYSCTL_RCGCGPIO_R EQU 0x400FE608
		EXPORT Start
		EXPORT GPIOPortF_Handler
		ENTRY
Start
	BL Port_Init
	  BL PF_Int_Init
	  MOV R4, #1
	  ;MSR PRIMASK, R4
	  MOV R0, #0xA1
LoopS
	ADD R1, R0, #1
	ADD R2, R1, #1
	ADD R3, R2, #1
	ADD R4, R3, #1
	ADD R5, R4, #1
	ADD R6, R5, #1
	ADD R0, R6, #1
	B LoopS
    
GPIOPortF_Handler
	PUSH {LR}
	BL Check_PF
	  POP {LR}
	  LDR R0, =GPIO_PORTF_ICR_R
	  MOV R1, #0x11
	  STR R1, [R0]
	  LDR R0, =cnt
	  LDR R1, [R0]
	  ADD R1, R1, #1
	  STR R1, [R0]
	  BX LR
      
      
B_PF0
	LDR R4, = GPIO_PORTF_DATA_R
	LDR R5, [R4]
	AND R5, R5, #0x2
	EOR R5, R5, #0x2
	STR R5, [R4]
	BX LR


B_PF4
	LDR R4, = GPIO_PORTF_DATA_R
	LDR R5, [R4]
    AND R5, R5, #0x4
	EOR R5, R5, #0x4
	STR R5, [R4]
	BX LR


Check_PF
	LDR R0, =GPIO_PORTF_RIS_R
	LDR R1, [R0]
	ANDS R2, R1, #0x01
	BNE B_PF0
	ANDS R2, R1, #0x10
	BNE B_PF4
	BX LR


PF_Int_Init
	MOV R1, #1
	MSR PRIMASK, R1
    
	  LDR R0, =GPIO_PORTF_IM_R
	  MOV R1, #0x00
	  STR R1, [R0]
	  LDR R0, =GPIO_PORTF_IS_R
	  MOV R1, #0x00 ; Edge detect
	  STR R1, [R0]
	  LDR R0, =GPIO_PORTF_IBE_R
	  MOV R1, #0x00 ; 1 Edge
	  STR R1, [R0]
	  LDR R0, =GPIO_PORTF_IEV_R
	  MOV R1, #0x00 ; Falling Edge detect
	  STR R1, [R0]
	  LDR R0, = NVIC_PRI7_R
	  LDR R1, =0xFF0FFFFF
	  LDR R2, [R0]
      
	AND R2, R2, R1
	  LDR R1, =0x00A00000 ; priority 5
	  ORR R2, R2, R1
	  STR R1, [R0]
	  LDR R0, = NVIC_EN0_R
	  LDR R1, =0x40000000
	  LDR R2, [R0]
	  ORR R2, R2, R1
	  STR R2, [R0]
	  MOV R2, #0x0
	  LDR R0, =GPIO_PORTF_IM_R
	  MOV R1, #0x11
	  STR R1, [R0]
      
	MOV R1, #0
	MSR PRIMASK, R1 ; store 0 to PRIMASK register to enable the global
intrrrupt

	BX LR
    
    
Port_Init
	; Enable Port F
	LDR R1, =SYSCTL_RCGCGPIO_R
	LDR R0, [R1]
	ORR R0, R0, #0x20
	STR R0, [R1]
	NOP
	NOP ; Wait for portF clock to stablize
; Port F Init, port F pin 4,0 for SW1, Sw2 respectively
LDR R0,=GPIO_PORTF_LOCK_R ; unlock portF
	LDR R1,=0x4C4F434B
	STR R1, [R0]
LDR R0,=GPIO_PORTF_CR_R
	MOV R1, #0xFF
	STR R1, [R0]
	LDR R0, =GPIO_PORTF_DIR_R ;input portF pin 4 and 0
	LDR R1, [R0]
	BIC R1, R1, #0x11
	;LDR R1, [R0]
	ORR R1, R1, #0xE; output portF pin 7,3-1
	STR R1, [R0]
LDR R0, =GPIO_PORTF_PUR_R
	LDR R1, [R0]
	ORR R1, R1, #0x11; pullup
	STR R1, [R0]
LDR R0, =GPIO_PORTF_AMSEL_R
	LDR R1, [R0]
	BIC R1, R1, #0x1F
	STR R1, [R0]
LDR R0, =GPIO_PORTF_DEN_R
	LDR R1, [R0]
	ORR R1, R1, #0x1F
	STR R1, [R0]
LDR R0, =GPIO_PORTF_AFSEL_R
	LDR R1, [R0]
	BIC R1, R1, #0x1F
	STR R1, [R0]
LDR R0, =GPIO_PORTF_PCTL_R
	LDR R1, [R0]
	LDR R2, =0xFFF00000
	AND R1, R1, R2 ;
	STR R1, [R0]
	;Initialize cnt
	LDR R0, =cnt
	LDR R1, =0x0
	STR R1, [R0]
	BX LR
	ALIGN
END
#include <stdint.h>

// Register Definitions
#define NVIC_PRI7_R (*((volatile uint32_t *)0xE000E41C))
#define NVIC_EN0_R (*((volatile uint32_t *)0xE000E100))
#define GPIO_PORTF_DATA_R (*((volatile uint32_t *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile uint32_t *)0x40025400))
#define GPIO_PORTF_IS_R (*((volatile uint32_t *)0x40025404))
#define GPIO_PORTF_IBE_R (*((volatile uint32_t *)0x40025408))
#define GPIO_PORTF_IEV_R (*((volatile uint32_t *)0x4002540C))
#define GPIO_PORTF_IM_R (*((volatile uint32_t *)0x40025410))
#define GPIO_PORTF_RIS_R (*((volatile uint32_t *)0x40025414))
#define GPIO_PORTF_ICR_R (*((volatile uint32_t *)0x4002541C))
#define GPIO_PORTF_AFSEL_R (*((volatile uint32_t *)0x40025420))
#define GPIO_PORTF_PUR_R (*((volatile uint32_t *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile uint32_t *)0x4002551C))
#define GPIO_PORTF_LOCK_R (*((volatile uint32_t *)0x40025520))
#define GPIO_PORTF_CR_R (*((volatile uint32_t *)0x40025524))
#define GPIO_PORTF_AMSEL_R (*((volatile uint32_t *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile uint32_t *)0x4002552C))
#define SYSCTL_RCGCGPIO_R (*((volatile uint32_t *)0x400FE608))

#define GPIO_LOCK_KEY 0x4C4F434B

// Function prototypes for global interrupt control
void DisableInterrupts(void); // Maps to CPSID I
void EnableInterrupts(void);  // Maps to CPSIE I

// Global variable
volatile uint32_t cnt = 0x0102;

// ***************** Port_Init *****************
// Initialize Port F pins for input and output
void Port_Init(void)
{
    volatile uint32_t delay;

    // Enable Port F clock
    SYSCTL_RCGCGPIO_R |= 0x20;
    delay = SYSCTL_RCGCGPIO_R; // Delay for clock to stabilize

    // Unlock Port F
    GPIO_PORTF_LOCK_R = GPIO_LOCK_KEY;
    GPIO_PORTF_CR_R = 0xFF;

    // Configure PF4, PF0 as inputs and PF3-PF1 as outputs
    GPIO_PORTF_DIR_R &= ~0x11; // Clear PF4, PF0
    GPIO_PORTF_DIR_R |= 0x0E;  // Set PF3, PF2, PF1

    // Enable pull-up resistors for PF4, PF0
    GPIO_PORTF_PUR_R |= 0x11;

    // Disable analog function
    GPIO_PORTF_AMSEL_R &= ~0x1F;

    // Enable digital I/O for PF4-PF0
    GPIO_PORTF_DEN_R |= 0x1F;

    // Disable alternate function
    GPIO_PORTF_AFSEL_R &= ~0x1F;

    // Clear Port control register for PF4-PF0
    GPIO_PORTF_PCTL_R &= 0xFFF00000;

    // Initialize cnt to 0
    cnt = 0;
}

// ***************** PF_Int_Init *****************
// Configure Port F interrupts (PF0, PF4)
void PF_Int_Init(void)
{
    DisableInterrupts(); // Disable global interrupts during setup

    // Disable Port F interrupts during configuration
    GPIO_PORTF_IM_R = 0x00;

    // Configure PF4 and PF0 for edge-sensitive interrupts
    GPIO_PORTF_IS_R = 0x00;  // Edge sensitive
    GPIO_PORTF_IBE_R = 0x00; // Not both edges
    GPIO_PORTF_IEV_R = 0x00; // Falling edge detect

    // Set priority 5 for Port F (Interrupt 30, bits 23-21 in PRI7)
    NVIC_PRI7_R = (NVIC_PRI7_R & 0xFF0FFFFF) | 0x00A00000;

    // Enable Interrupt 30 in NVIC (Bit 30 in EN0)
    NVIC_EN0_R |= 0x40000000;

    // Unmask interrupts for PF4 and PF0
    GPIO_PORTF_IM_R = 0x11;

    EnableInterrupts(); // Enable global interrupts
}

// ***************** GPIOPortF_Handler *****************
// ISR for Port F
void GPIOPortF_Handler(void)
{
    // Check if PF0 caused the interrupt
    if (GPIO_PORTF_RIS_R & 0x01)
    {
        // Toggle PF1 (equivalent to the AND/EOR logic in assembly)
        GPIO_PORTF_DATA_R = (GPIO_PORTF_DATA_R & 0x02) ^ 0x02;
    }

    // Check if PF4 caused the interrupt
    if (GPIO_PORTF_RIS_R & 0x10)
    {
        // Toggle PF2
        GPIO_PORTF_DATA_R = (GPIO_PORTF_DATA_R & 0x04) ^ 0x04;
    }

    // Acknowledge the interrupt by clearing the flags for PF4 and PF0
    GPIO_PORTF_ICR_R = 0x11;

    // Increment global counter
    cnt = cnt + 1;
}

// ***************** main *****************
int main(void)
{
    volatile uint32_t dummy_r0, dummy_r1, dummy_r2, dummy_r3, dummy_r4, dummy_r5, dummy_r6;

    Port_Init();
    PF_Int_Init();

    // Simulate the dummy addition loop in the assembly 'Start' routine
    dummy_r0 = 0xA1;
    while (1)
    {
        dummy_r1 = dummy_r0 + 1;
        dummy_r2 = dummy_r1 + 1;
        dummy_r3 = dummy_r2 + 1;
        dummy_r4 = dummy_r3 + 1;
        dummy_r5 = dummy_r4 + 1;
        dummy_r6 = dummy_r5 + 1;
        dummy_r0 = dummy_r6 + 1;
    }

    return 0;
}

1.Register Mapping

가장 기본입니다. 어셈블리의 단순한 상수 정의(EQU)를 C 언어에서는 "이 주소는 메모리가 아니라 하드웨어 핀이니까 맘대로 최적화하지 말고 직접 건드려!"라는 뜻의 volatile 포인터로 캐스팅해야 합니다.

Assembly:

GPIO_PORTF_DIR_R EQU 0x40025400

C Language:

// Map hardware address using volatile pointer
#define GPIO_PORTF_DIR_R (*((volatile uint32_t *)0x40025400))

2. 특정 비트만 1로 켜기 (Set Bits)

임베디드에서 가장 많이 쓰는 Read-Modify-Write 패턴입니다. 기존 값을 읽어와서(LDR), 특정 비트만 1로 합치고(ORR), 다시 저장(STR)하는 3줄이 C 언어에서는 |= 하나로 끝납니다.

Assembly:

LDR R0, =GPIO_PORTF_DEN_R   ; 1. Load address into R0
LDR R1, [R0]                ; 2. Read current value into R1
ORR R1, R1, #0x1F           ; 3. Bitwise OR to set bits 0-4
STR R1, [R0]                ; 4. Store modified value back

코드를 입력하세요

C Language:
```c
// Read, set bits 0-4 to 1, and write back
GPIO_PORTF_DEN_R |= 0x1F;

3. 특정 비트만 0으로 끄기 (Clear Bits)

이 부분이 시험에서 가장 많이 헷갈리는 구간입니다. 어셈블리의 BIC(Bit Clear) 명령어는 명시한 비트를 0으로 밀어버립니다. C 언어에서는 이를 "반전시킨 값과 AND 연산(&= ~)" 하는 방식으로 똑같이 구현합니다.

Assembly:

LDR R0, =GPIO_PORTF_DIR_R
LDR R1, [R0]
BIC R1, R1, #0x11           ; Clear bit 4 and bit 0
STR R1, [R0]

C Language:

// Read, clear bits 4 and 0, and write back
GPIO_PORTF_DIR_R &= ~0x11;

4. 특정 비트 뒤집기 (Toggle Bits)

회원님의 어셈블리 코드에서 스위치가 눌렸을 때 LED를 껐다 켰다(토글)하는 핵심 로직입니다. 어셈블리의 EOR(Exclusive OR)는 C 언어의 ^= (XOR) 연산자와 완벽하게 대응합니다.

Assembly (B_PF0 라벨 부분):

LDR R4, =GPIO_PORTF_DATA_R
LDR R5, [R4]
AND R5, R5, #0x2            ; Isolate bit 1 (PF1)
EOR R5, R5, #0x2            ; Toggle bit 1 using XOR
STR R5, [R4]

C Language:

// Isolate bit 1 and toggle it using XOR
GPIO_PORTF_DATA_R = (GPIO_PORTF_DATA_R & 0x02) ^ 0x02;

5. 조건문 분기 (If Condition / Interrupt Check)

인터럽트가 발생했을 때 PF0 스위치가 눌렸는지, PF4 스위치가 눌렸는지 검사하는 로직입니다. 어셈블리는 ANDS(AND 연산 후 상태 플래그 업데이트)와 BNE(0이 아니면 점프)를 조합해서 씁니다.

Assembly (Check_PF 라벨 부분):

LDR R0, =GPIO_PORTF_RIS_R
LDR R1, [R0]
ANDS R2, R1, #0x01          ; Check if bit 0 is 1
BNE B_PF0                   ; If not zero (True), branch to B_PF0

C Language:

// Check if PF0 caused the interrupt (bit 0 is 1)
if(GPIO_PORTF_RIS_R & 0x01) {
    // Execute B_PF0 logic
}

6. 메모리(전역 변수) 값 증가시키기

단순히 레지스터가 아니라 RAM에 있는 전역 변수 cnt의 값을 1 올리는 작업도 구조는 똑같습니다.

Assembly:

LDR R0, =cnt                ; Load memory address of 'cnt'
LDR R1, [R0]                ; Read value from memory
ADD R1, R1, #1              ; Add 1
STR R1, [R0]                ; Store value back to memory

C Language:

// Read memory, add 1, write back to memory
cnt = cnt + 1;
profile
RTL, FPGA Engineer

0개의 댓글