240213

Yonggeun Park·2024년 2월 13일
0

Programmer's 모델

명령어

32비트 ARM 명령어

  • 모든 명령어는 조건부 실행이 가능
  • 메모리 참조 명령, 상대주소 지정방식<->적치 데이터
  • immediate 상수는 32비트 명령어 내 표시
  • 32비트 고정 명령 길이를 사용해서 pipeline 구성이 용이하고 빠르며, 디코더 구현이 쉽다
  • ARM 명령어 요약

16비트 Thumb 명령어 : 메모리 절약

  • 코드의 크기를 줄일 수 있다
  • 조건부 실행이 안된다

초기화 시 arm 명령어가 되고 thumb명령어로 가고싶으면 위의 BX를 사용한다

8비트 Java 명령어 : 바이트 코드라고도 함

동작모드

  • 현재 프로세서가 어떤 권한을 가지고 어떤 종류의 작업을 하고 있는지를 나타냄
  • user mode : 어플리케이션 수행할 때의 모드
  • suvervisor mode : 시스템 자원 관리, 동작 시스템의 커널이나 드라이버 처리, SWI 발생시
  • abort mode : 오류가 발생 시, 예외 중 하나
    segmentation fault : 메모리 주소를 잘못 접근할 때 발생
  • 예외처리 : 대부분 operationg 모드는 외부 조건에 의해 arm 프로세서가 하드웨어적으로 변함
  • 시스템 콜 : user모드에서 supervisor모드로 전환하여 시스템자원 사용

<vectors.S> 테이블
줄당 4번지가 바뀐다
power on reset
BOD reset
reset

레지스터

프로세서가 작업을 하는데 사용되는 값을 임시저장하는 공간

  • cpu 속도와 동일한 고속

  • 실사용 16개, 모드마다 shadow 레지스터가 따로있다, 총 37개

  • 30개의 범용

  • 1개의 PC - R15번(코드의 주소를 불러옴)

  • 1개의 CPSR - 상태 레지스터

  • 5개의 SPSR

    ARM state
    16개의 범용
    R13(stack point)
    R14(link register)
    R15(program counter)

    FIQ가 IRQ보다 빠르다

SP : 프로그램에서 사용하는 스택의 위치를 저장하는 레지스터(R13)
최초에 할당되지 않은 4바이트를 가리키고 있다
arm은 별도의 스택 명령이 없음
지역변수는 자동으로 메모리 관리(free 안해도 된다)
push, pop 없음

LR : 서브루틴에서 되돌아 갈 위치 정보를 저장하고 있는 레지스터(R14)
BL 명령으로 PC값을 자동으로 LR에 저장

PC : 프로그램 수행하는 위치 저장하는 레지스터(R15)

메모리 구조

  • 메모리는 프로그램과 데이터를 저장하는 공간
  • big/little endian 지원
  • 4바이트

예외처리

  • 외부 요청이나 오류에 의해 프로그램을 멈추고 동작모드 변환해 오류처리를 하도록 하는 것
  • 0번지에 벡터 테이블을 둔다
  • 우선순위를 지정
  • 예외처리 과정

ARM 프로세서 명령어

  • STM IDE debug 에서 16/32 선택 가능
  • Thumb-2 : 코드는 줄고 속도는 좋아졌다

32비트 arm 명령어 구조

$ cd pi_bsp/u-boot/arch/arm/cpu/armv7
$ cp start.S /srv/samba/
$ arm-linux-gnueabihf-objdump -S start.o > start.txt
$ vi start.txt



접미사 S를 붙이면 상태 레지스터에 반영해라
없으면 항상(무조건, AL) 실행

mov r2, #8
0xe3a02008 = 1110 0011 1010 0000 0010 0000 0000 1000
			  AL  

2번째의 00은 데이터 프로세스 명령어라는 뜻
뒤의 1이

위 사진에서 1임을 알 수 있다
그리고 4개 읽으면 1101이다

접미사를 안썼기 때문에 다음에 0이 와서 unset이다

16~19는 소스레지스터인데 우리는 상수를 썼기 때문에 0이다
12~16는 2인데, 이것이 r2를 의미한다
나머지 12개는 적치 상수인데, 8이므로 8을 의미한다 -> #8

.71에서 파일을 내 우분투 삼바로 가져와서 복사한 뒤

원래 있던 start.S를 다른 이름으로 변경하고 가져온 파일을 start.S로 이름 바꾼 뒤

armv7에 복사한다
그리고 u-boot에서 ./build.sh로 실행하면 start.o가 생기고 u-boot.bin을 nfs로 파이에 보낸다

그 뒤에 /boot/firmware에 옮기고 재부팅하면

이 화면에서 멈추고
LED가 좌우로 왔다갔다 하며, 버튼 S7을 누르면 부팅이 시작된다!

새 명령어 추가하기

~/pi_bsp/u-boot/common$ vi cmd_kcci_led.c

#include <common.h>
#include <command.h>
#include <asm/io.h>

#define BCM2711_GPIO_GPFSEL0 0xFE200000
#define BCM2711_GPIO_GPFSEL1 0xFE200004
#define BCM2711_GPIO_GPFSEL2 0xFE200008
#define BCM2711_GPIO_GPSET0 0xFE20001C
#define BCM2711_GPIO_GPCLR0 0xFE200028
#define BCM2711_GPIO_GPLEV0 0xFE200034

#define GPIO6_9_SIG_OUTPUT 0x09240000
#define GPIO10_13_SIG_OUTPUT 0x00012249 //txd,rxd

void led_init(void)
{
	writel(GPIO6_9_SIG_OUTPUT, BCM2711_GPIO_GPFSEL0);
    writel(GPIO10_13_SIG_OUTPUT, BCM2711_GPIO_GPFSEL1);
}

void led_write(unsigned long led_data)
{
	writel(0x3fc0, BCM2711_GPIO_GPCLR0);  //led all off
    led_data = led_data << 6;
    writel(led_data, BCM2711_GPIO_GPSET0);  //ledX on
}

static int do_KCCI_LED(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
{
	unsigned long led_data;
    if(argc != 2)
    {
    	cmd_usage(cmdtp);
        return 1;
    }
    
    printf("*LED TEST START\n");
    led_init();
    led_data = simple_strtoul(argv[1], NULL, 16);
    led_write(led_data);
    printf("*LED TEST END(%s : %#04x)\n\n", argv[0], (unsigned int)led_data);
    
    return 0;
}

U_BOOT_CMD(led, 2, 0, do_KCCI_LED, "led - kcci LED Test", "number - Input argument is only one.(led [0x00~0xff])\n");

작성을 해주고
$ vi Makefile

8번째 줄에 
obj-y += cmd_kcci_led.o
를 추가해준다

이후 cd ..
$ ./build.sh
$ cp u-boot.bin /srv/nfs
해준 뒤

라즈베리파이 측에서
$ cp /mnt/ubuntu_nfs/u-boot.bin /boot/firmware
옮기고
라즈베리를 다시 시작해서 u-boot로 진입한다
그 이후
led 0x55, led oxff, led 0x00 등 명령을 입력해서 led를 키고 끈다

부트로드, 커널은 동적으로 사용할 수 없다

펌웨어에서 주의할 점
GPIO를 이미 사용중인데, 0으로 바꿔버리면 안된다
read modify write의 순서를 가져야함
32비트의 값을 read 하고, 기존에 사용중인 것은 두고 나머지를 0으로 설정한 뒤(00001111과 and 연산자) 원하는 값으로 바꿔준다(10110000과 or 연산자)(modify)그리고 write를 해야한다
예)10110100 and 00001111 = 00000100 / 00000100 or 10110000 = 10110100
여태는 라이브러리만 사용해왔어서 됐지만 원래는 안된다

비트 밴딩 >> 클럭 소모가 많이 되므로 남은 주소의 일부분을 한개의 비트에 한개의 주소를 다 주었다 그래서 속도가 빨라짐(MCU마다 지원될 수도 있고 안될 수도 있다)

CLR, set는 1일 때 clear, set 한다
11111111000000 = 0x3fc0

profile
Dragon_muscle

0개의 댓글

관련 채용 정보