2015-01-20 1 views
4

저는 GameBoy 프로그래밍을 배우는 데 많은 시간을 보내고 있습니다. 이미 Z80 어셈블리에 익숙했기 때문에 그것을 사용하는 것을 두려워하지 않았습니다. (물론) C 또는 C++로 프로그래밍하는 것이 훨씬 더 생산적이지만, GameBoy의 전체 컴파일러를 찾을 수는 없으며, 모든 것을 스스로 관리하고 프로그래머에게 시스템 레지스터에 대한 액세스 권한을 부여하지 않으며, 100 % CPU 사용률 및 인터럽트 지원과 같은 끔찍한 단점.
Arduino의 AVR 컴파일러처럼 시스템 레지스터를 처리 할 수 ​​있습니까? DDRD = %10101011
인터럽트 및 시스템 레지스터를 컴파일러에 추가하려면 어떻게해야합니까? 하나의 시스템 레지스터를 제외하고는 모두 1 바이트 메모리 주소이고 인터럽트 벡터는 물론 메모리 위치입니다. 메모리 주소가 아닌 유일한 시스템 레지스터는 두 개의 어셈블리 명령어 EIDI으로 만 수정할 수 있지만 인라인 함수 일 수 있습니다 ?시스템 레지스터와 인터럽트가있는 GameBoy 컴파일러

+1

[GBDK] (http://gbdk.sourceforge.net/)는 'gb/hardware.h'를 사용하여 레지스터와 직접 상호 작용할 수있는 C 컴파일러입니다. 그러나 제공된 설명서는 좋지 않으므로 실제로 문서에있는 이름을 볼 수 없습니다. 'include/gb/hardware.h'에서 파일을 열면 모든 것을 볼 수 있습니다. 또한 인터럽트 지원을 가지고 있습니다 - ['gb/gb.h']에서'add_VBL','add_LCD','add_TIM','add_SIO','add_JOY'를보십시오 (http://gbdk.sourceforge.net/doc/ html/gb.h.html). – Pokechu22

+0

와우 덕분에 @ Pokechu22. 죄송 합니다만 제때에 대답하지 않으 셨습니다. –

답변

6

일반적인 방법은 시스템 레지스터에 대한 자체 포인터를 만드는 것입니다. 나는 DDRD의 주소를 모르는, 그러나이 같은 트릭을하기 위해해야 ​​

volatile unsigned char *reg_DDRD = (unsigned char *)0xE000; 
*reg_DDRD = 0xAB; 

대부분의 C 컴파일러는 이진 상수를 지원하지 않습니다하지만 당신은 몇 가지 매크로 해커로 사용할 수 있습니다. 컴파일러를 수정하는 것은 의미가 없습니다

#define DDRD (*reg_DDRD) 
DDRD = 0xAB; 

바닐라 C 코드와 마찬가지로 잘 작동 할 수있을 때 : 그리고 당신은 조금 더 직관적 인 구문을 만들기 위해 매크로를 사용할 수 있습니다.

인터럽트 처리는 3 가지 문제를 해결합니다. 첫 번째는 인터럽트 벡터 주소가 C 함수로 점프하는 것입니다. ROM에 있으므로 C 런타임 환경을 수정하여 초기화해야합니다. 이 꽤 시스템이 따라 얻을 수 있지만, 보통 싶은 것은 다음과 같습니다 어셈블리 언어 파일을 추가 할 수 있습니다 : 이것은 CPU가 C 프로그램에서 intr_function()로 이동하게한다

 org 38h ; or wherever the gameboy CPU jumps to on interrupt 
jp _intr_function 

합니다. 맨 앞에 밑줄이 필요할 수도 있고 없을 수도 있습니다. 그리고 어셈블러 파일의 대상 주소를 org으로 설정하지 못할 수도 있지만 대신 링커와 섹션을 어루 만져야합니다.

두 번째 문제는 C 함수가 반드시 필요한 모든 레지스터를 저장하지 않는다는 것입니다. 이러한 라인을 따라, 그것을 인라인 어셈블리를 추가하여이 작업을 수행 할 수 있습니다 :

void intr_function() 
{ 
    asm(" push af"); 
    asm(" push bc"); 
    asm(" push de"); 
    asm(" push hl"); 

    // ... now do what you like here. 

    asm(" pop hl"); 
    asm(" pop de"); 
    asm(" pop bc"); 
    asm(" pop af"); 
} 

마지막으로, 인터럽트는 하드웨어 레지스터를 조작하여 인정해야 할 수 있습니다. 그러나 C 코드에서 그렇게 할 수 있으므로 특별한 점은 없습니다.

wait 루프와 관련된 문제가 명확하지 않습니다. 표준 C 컴파일러는 main()을 호출하고 루프를 원한다면 당신에게 달려있다. Arduino SDK에 사용 된 C와 같은 언어에는 사용자가 작성한 함수를 호출하는 자체 내장 무한 루프가 있지만 사실이 아닙니다.

+1

사실상 모든 공급 업체에서 제공하는 헤더 파일이이 작업을 어떻게 처리하는지는 사실입니다. Z80 내부 구조에 친숙하지는 않지만 포인터가 반드시 포인터 일 필요는없는 아키텍처를 알고 있어야합니다. 특별 지시를 통해서만 액세스 할 수있는 은행 개폐 및 별도의 주소 공간이 있으므로 C의 평면 메모리 주소 공간에 대한보기가 유효하지 않게됩니다. –

+0

@JonathonReinhart GameBoy는 은행 전환을 사용하지만 운 좋게도 16K의 ROM만으로 시스템 레지스터가 절대로 움직이지 않습니다. –

+0

@LeeAllan 설명해 주셔서 감사합니다. 나는 그들이 시스템을 상호 작용하기가 어렵게 만들 것이라고 기대하지 않았다. –

3

먼저 GBDK을 사용할 수 있습니다. Gameboy 용 C 컴파일러 및 라이브러리. gb/hardware.h에있는 레지스터에 대한 액세스를 제공하지만 (개별 레지스터에 대한 설명이 없기 때문에 doc 파일에는 나열되지 않습니다).또한 gb/gb.h : add_VBL, add_LCD, add_TIM, add_SIOadd_JOY의 방법을 통해 인터럽트에 대한 액세스를 제공합니다. (remove_이라는 메소드도 제거됩니다.)

참조 및/또는 자신의 사용을 위해, 여기 gb/hardware.h의 내용이다 :

#define __REG volatile UINT8 * 

#define P1_REG  (*(__REG)0xFF00) /* Joystick: 1.1.P15.P14.P13.P12.P11.P10 */ 
#define SB_REG  (*(__REG)0xFF01) /* Serial IO data buffer */ 
#define SC_REG  (*(__REG)0xFF02) /* Serial IO control register */ 
#define DIV_REG  (*(__REG)0xFF04) /* Divider register */ 
#define TIMA_REG (*(__REG)0xFF05) /* Timer counter */ 
#define TMA_REG  (*(__REG)0xFF06) /* Timer modulo */ 
#define TAC_REG  (*(__REG)0xFF07) /* Timer control */ 
#define IF_REG  (*(__REG)0xFF0F) /* Interrupt flags: 0.0.0.JOY.SIO.TIM.LCD.VBL */ 
#define NR10_REG (*(__REG)0xFF10) /* Sound register */ 
#define NR11_REG (*(__REG)0xFF11) /* Sound register */ 
#define NR12_REG (*(__REG)0xFF12) /* Sound register */ 
#define NR13_REG (*(__REG)0xFF13) /* Sound register */ 
#define NR14_REG (*(__REG)0xFF14) /* Sound register */ 
#define NR21_REG (*(__REG)0xFF16) /* Sound register */ 
#define NR22_REG (*(__REG)0xFF17) /* Sound register */ 
#define NR23_REG (*(__REG)0xFF18) /* Sound register */ 
#define NR24_REG (*(__REG)0xFF19) /* Sound register */ 
#define NR30_REG (*(__REG)0xFF1A) /* Sound register */ 
#define NR31_REG (*(__REG)0xFF1B) /* Sound register */ 
#define NR32_REG (*(__REG)0xFF1C) /* Sound register */ 
#define NR33_REG (*(__REG)0xFF1D) /* Sound register */ 
#define NR34_REG (*(__REG)0xFF1E) /* Sound register */ 
#define NR41_REG (*(__REG)0xFF20) /* Sound register */ 
#define NR42_REG (*(__REG)0xFF21) /* Sound register */ 
#define NR43_REG (*(__REG)0xFF22) /* Sound register */ 
#define NR44_REG (*(__REG)0xFF23) /* Sound register */ 
#define NR50_REG (*(__REG)0xFF24) /* Sound register */ 
#define NR51_REG (*(__REG)0xFF25) /* Sound register */ 
#define NR52_REG (*(__REG)0xFF26) /* Sound register */ 
#define LCDC_REG (*(__REG)0xFF40) /* LCD control */ 
#define STAT_REG (*(__REG)0xFF41) /* LCD status */ 
#define SCY_REG  (*(__REG)0xFF42) /* Scroll Y */ 
#define SCX_REG  (*(__REG)0xFF43) /* Scroll X */ 
#define LY_REG  (*(__REG)0xFF44) /* LCDC Y-coordinate */ 
#define LYC_REG  (*(__REG)0xFF45) /* LY compare */ 
#define DMA_REG  (*(__REG)0xFF46) /* DMA transfer */ 
#define BGP_REG  (*(__REG)0xFF47) /* BG palette data */ 
#define OBP0_REG (*(__REG)0xFF48) /* OBJ palette 0 data */ 
#define OBP1_REG (*(__REG)0xFF49) /* OBJ palette 1 data */ 
#define WY_REG  (*(__REG)0xFF4A) /* Window Y coordinate */ 
#define WX_REG  (*(__REG)0xFF4B) /* Window X coordinate */ 
#define KEY1_REG (*(__REG)0xFF4D) /* CPU speed */ 
#define VBK_REG  (*(__REG)0xFF4F) /* VRAM bank */ 
#define HDMA1_REG (*(__REG)0xFF51) /* DMA control 1 */ 
#define HDMA2_REG (*(__REG)0xFF52) /* DMA control 2 */ 
#define HDMA3_REG (*(__REG)0xFF53) /* DMA control 3 */ 
#define HDMA4_REG (*(__REG)0xFF54) /* DMA control 4 */ 
#define HDMA5_REG (*(__REG)0xFF55) /* DMA control 5 */ 
#define RP_REG  (*(__REG)0xFF56) /* IR port */ 
#define BCPS_REG (*(__REG)0xFF68) /* BG color palette specification */ 
#define BCPD_REG (*(__REG)0xFF69) /* BG color palette data */ 
#define OCPS_REG (*(__REG)0xFF6A) /* OBJ color palette specification */ 
#define OCPD_REG (*(__REG)0xFF6B) /* OBJ color palette data */ 
#define SVBK_REG (*(__REG)0xFF70) /* WRAM bank */ 
#define IE_REG  (*(__REG)0xFFFF) /* Interrupt enable */ 

이 따라서 George Phillips's answer과 같은 방법으로 수행하고있다는 일반 변수처럼 사용할 수 있습니다.

GBDK에서 인터럽트를 추가하고 제거하는 데 사용되는 코드는 libc\gb\crt0.s에 있지만이 게시물의 관련 섹션을 포함 할만큼 어셈블리가 부족한 것 같습니다.

바쁜 루프를 피하는 방법에 대해 잘 모르겠습니다.

관련 문제