저는 GameBoy 프로그래밍을 배우는 데 많은 시간을 보내고 있습니다. 이미 Z80 어셈블리에 익숙했기 때문에 그것을 사용하는 것을 두려워하지 않았습니다. (물론) C 또는 C++로 프로그래밍하는 것이 훨씬 더 생산적이지만, GameBoy의 전체 컴파일러를 찾을 수는 없으며, 모든 것을 스스로 관리하고 프로그래머에게 시스템 레지스터에 대한 액세스 권한을 부여하지 않으며, 100 % CPU 사용률 및 인터럽트 지원과 같은 끔찍한 단점.
Arduino의 AVR 컴파일러처럼 시스템 레지스터를 처리 할 수 있습니까? DDRD = %10101011
인터럽트 및 시스템 레지스터를 컴파일러에 추가하려면 어떻게해야합니까? 하나의 시스템 레지스터를 제외하고는 모두 1 바이트 메모리 주소이고 인터럽트 벡터는 물론 메모리 위치입니다. 메모리 주소가 아닌 유일한 시스템 레지스터는 두 개의 어셈블리 명령어 EI
및 DI
으로 만 수정할 수 있지만 인라인 함수 일 수 있습니다 ?시스템 레지스터와 인터럽트가있는 GameBoy 컴파일러
답변
일반적인 방법은 시스템 레지스터에 대한 자체 포인터를 만드는 것입니다. 나는 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와 같은 언어에는 사용자가 작성한 함수를 호출하는 자체 내장 무한 루프가 있지만 사실이 아닙니다.
사실상 모든 공급 업체에서 제공하는 헤더 파일이이 작업을 어떻게 처리하는지는 사실입니다. Z80 내부 구조에 친숙하지는 않지만 포인터가 반드시 포인터 일 필요는없는 아키텍처를 알고 있어야합니다. 특별 지시를 통해서만 액세스 할 수있는 은행 개폐 및 별도의 주소 공간이 있으므로 C의 평면 메모리 주소 공간에 대한보기가 유효하지 않게됩니다. –
@JonathonReinhart GameBoy는 은행 전환을 사용하지만 운 좋게도 16K의 ROM만으로 시스템 레지스터가 절대로 움직이지 않습니다. –
@LeeAllan 설명해 주셔서 감사합니다. 나는 그들이 시스템을 상호 작용하기가 어렵게 만들 것이라고 기대하지 않았다. –
먼저 GBDK을 사용할 수 있습니다. Gameboy 용 C 컴파일러 및 라이브러리. gb/hardware.h
에있는 레지스터에 대한 액세스를 제공하지만 (개별 레지스터에 대한 설명이 없기 때문에 doc 파일에는 나열되지 않습니다).또한 gb/gb.h
: add_VBL
, add_LCD
, add_TIM
, add_SIO
및 add_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
에 있지만이 게시물의 관련 섹션을 포함 할만큼 어셈블리가 부족한 것 같습니다.
바쁜 루프를 피하는 방법에 대해 잘 모르겠습니다.
[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
와우 덕분에 @ Pokechu22. 죄송 합니다만 제때에 대답하지 않으 셨습니다. –