Changing the Init code from GB Classic to GB Color (RGBASM)

Discussion of programming and development for the original Game Boy and Game Boy Color.
sdm
Posts: 424
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Changing the Init code from GB Classic to GB Color (RGBASM)

Post by sdm »

I would like to modify the current RGBASM code for Game Boy Classic to Game Boy Color.

What do I need to modify? There are a lot of descriptions related to GB Classic, but I can't find specific information about GBC.

Additionally, if I use the MBC1 mapper in the code, can it remain in GBC or do I have to change the mapper to e.g. MBC5? (Can it be left since MBC5 is downward compatible with MBC1?)

In "Cartridge Header" I have the following selected:

Code: Select all

;	DB	$C0						; GBC flag

Code: Select all

"0143 - CGB Flag
In older cartridges this byte has been part of the Title (see above). In CGB cartridges the upper bit is used to enable CGB functions.
This is required, otherwise the CGB switches itself into Non-CGB-Mode. Typical values are:

 80h - Game supports CGB functions, but works on old gameboys also.
 C0h - Game works on CGB only (physically the same as 80h)."
When I use it, compilation gives an error:

"error: Unable to place "Cartridge Header" (ROM0 section) at address $0100: section overlaps with "Program Start"

The code compiles using these arguments:

Code: Select all


@echo off

set name="demo"

set path=rgbds\

rgbasm -o %name%.o %name%.asm 
rgblink -o %name%.gbc %name%.o 
rgbfix -c -C -v -p 0 %name%.gbc

echo Done.

del *.o

pause 

In the RGBFIX documentation I have:

-C, --color-only
Set the Game Boy Color–only flag: 0x143 = 0xC0. If both this and the -c flag are set, this takes precedence.
-c, --color-compatible
Set the Game Boy Color–compatible flag: 0x143 = 0x80. If both this and the -C flag are set, -C takes precedence.


What changes do I need to make to set the code for GBC?



Current INIT code for GB Classic:

Code: Select all


;----------------------------------------------------------

	INCLUDE	"hardware.inc"

;----------------------------------------------------------
; RESTART VECTORS:
;----------------------------------------------------------

	SECTION	"RST_00",ROM0[$0000]
	RET

	SECTION	"RST_08",ROM0[$0008]
	RET

	SECTION	"RST_10",ROM0[$0010]
	RET

	SECTION	"RST_18",ROM0[$0018]
	RET

	SECTION	"RST_20",ROM0[$0020]
	RET

	SECTION	"RST_28",ROM0[$0028]
	RET

	SECTION	"RST_30",ROM0[$0030]
	RET

	SECTION	"RST_38",ROM0[$0038]
	RET

;----------------------------------------------------------
; INTERRUPT VECTORS:
;----------------------------------------------------------

	SECTION	"VBL Interrupt Vector",ROM0[$0040]
	JP VBlank_Handler

	SECTION	"LCD Interrupt Vector",ROM0[$0048]
	RETI

	SECTION	"TIM Interrupt Vector",ROM0[$0050]
	RETI

	SECTION	"SIO Interrupt Vector",ROM0[$0058]
	RETI

	SECTION	"JOY Interrupt Vector",ROM0[$0060]
	RETI

;----------------------------------------------------------
; CARTRIDGE HEADER:
;----------------------------------------------------------

	SECTION	"Cartridge Header",ROM0[$0100]

	NOP

	JP StartPoint

	NINTENDO_LOGO
; 134

	DB	"0123456789ABCDEF"
;	DB	$C0						; Gbc flag

; 144
	DB	0,0						; LICENCEE
	DB	0						; SGB FLaG
	DB	1						; CaRTTYPE ; 1=MBC1
	DB	0						; ROMSIZE
	DB	0						; RaMSIZE
	DB	$01						; destination (0 = Japan, 1 = Non Japan)
	DB	$00						; Manufacturer
	DB	0						; Version
	DB	0						; Complement check
	DW	0						; Checksum

;----------------------------------------------------------
; INITIALIZE THE GAMEBOY:
;----------------------------------------------------------

	SECTION	"Program Start",ROM0[$0150]

StartPoint:

	DI

	XOR A
	LDH [rNR52],A						; Switch off sound
	LDH [rSCY],A						; Scroll
	LDH [rSCX],A						; Scroll

	CALL Screen_OFF

;----------------------------------------------------------

ClearWRAM:

	XOR A
	LD HL,$C000						; ram is at $c000-cfff
	LD BC,$1000						; orig GB had this internal

ClearWRAM_Loop:

	LD [HL+],A
	DEC C
	JR NZ,ClearWRAM_Loop
	DEC B
	JR NZ,ClearWRAM_Loop

;----------------------------------------------------------

	LD SP, $CFFF						; stack pointer

;----------------------------------------------------------

ClearHiRAM:

	LD B,$7F						; # bytes
	LD C,$80						; hiram ff80-fffe

ClearHiRAM_Loop:

;	LD [C],A
	LD [$FF00+C],A
	INC C
	DEC B
	JR NZ,ClearHiRAM_Loop

;----------------------------------------------------------

ClearVRAM:

	LD HL,$8000						; vram is at $c000-dfff
	LD BC,$2000						; orig GB had this internal

ClearVRAM_Loop:

	LD [HL+],A
	DEC C
	JR NZ,ClearVRAM_Loop
	DEC B
	JR NZ,ClearVRAM_Loop

;----------------------------------------------------------

ClearOAM:

	LD B,$A0						; # bytes
	LD HL,$FE00						; oam

ClearOAM_Loop:

	LD [HL+],A
	DEC B
	JR NZ,ClearOAM_Loop	

	LD HL,run_dma_master					; copy oam routine to hiram
	LD DE,run_dma
	LD BC,run_dma_end-run_dma_master
	CALL memcpy 	

;----------------------------------------------------------

	LD A,$E4						; 11 10 01 00 ; load a palette
	LDH [rBGP],A
	LDH [rOBP0],A
	LD A,$90						; 10 01 00 00 ; lighter
	LDH [rOBP1],A
	XOR A							; vblank interrupt on
	LDH [rIF],A						; clear flags

	LD A,IEF_VBLANK						; allow vblanks to trip halt
	LDH [rIE],A

	LD A,%10010011						; screen on (10010011)
	LD [LCD_Settings],A
								; bit 7 = LCDCF_ON = 1
								; bit 6 = window tiles 9800 = 0
								; bit 5 = window off = 0
								; bit 4 = bg tiles 8000 = 1
								; bit 3 = tile map #0 9800 = 0
								; bit 2 = sprite 8x8 = 0
								; Bit 1 - OBJ (Sprite) Display Enable    (0=Off, 1=On)
								; bit 0 = background display = 1 = on
	CALL Screen_ON
	EI							; allow the vblank to set an inturrupt, so halt can work

;----------------------------------------------------------

Forever:

	HALT							; the assembler seems to be auto adding a nop
	NOP

	JP Forever
	
;----------------------------------------------------------

memcpy:								; Copies BC bytes from HL to DE.
								; Increment B if C is nonzero
	DEC BC
	INC B
	INC C

memcpy_loop:

	LD A,[HL+]
	LD [DE],A
	INC DE
	DEC C
	JR NZ,memcpy_loop
	DEC b
	JR NZ,memcpy_loop

	RET

;----------------------------------------------------------

Run_DMA_Master:

	LD A,$CF						; CF00 ram = OAM Mirror/Buffer.
	LDH [rDMA],A
	LD A,40

Run_DMA_Master_Loop:

	DEC A

	JR NZ,Run_DMA_Master_Loop

	RET

Run_DMA_End:

;----------------------------------------------------------

Screen_OFF:

	LDH A,[rLCDC]
	AND A,LCDCF_ON
	JR Z,Screen_LCD_OFF

	LD B,$91
	CALL wait_ly

	XOR A
	LDH [rLCDC],A						; Shutdown LCD

Screen_LCD_OFF:
	RET


hardware.inc

Code: Select all

;*
;* Gameboy Hardware definitions
;*
;* Based on Jones' hardware.inc
;* And based on Carsten Sorensen's ideas.
;*
;* Rev 1.1 - 15-Jul-97 : Added define check
;* Rev 1.2 - 18-Jul-97 : Added revision check macro
;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05
;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes
;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines
;*                     :  and Nintendo Logo
;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC
;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1
;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC
;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format
;* Rev 2.0 -           : Added GBC registers
;* Rev 2.1 -           : Added MBC5 & cart RAM enable/disable defines
;* Rev 2.2 -           : Fixed NR42,NR43, & NR44 equates
;* Rev 2.3 -           : Fixed incorrect _HRAM equate
;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND)
;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND)

; If all of these are already defined, don't do it again.

    IF !DEF(HARDWARE_INC)
HARDWARE_INC = 1

rev_Check_hardware_inc : MACRO
;NOTE: REVISION NUMBER CHANGES MUST BE ADDED
;TO SECOND PARAMETER IN FOLLOWING LINE.
    IF  \1 > 2.5 ;PUT REVISION NUMBER HERE
        WARN    "Version \1 or later of 'hardware.inc' is required."
    ENDC
ENDM

_HW          EQU $FF00

_VRAM        EQU $8000 ; $8000->$A000
_SCRN0       EQU $9800 ; $9800->$9BFF
_SCRN1       EQU $9C00 ; $9C00->$9FFF
_RAM         EQU $C000 ; $C000->$E000
_OAMRAM      EQU $FE00 ; $FE00->$FE9F
_AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F
_HRAM        EQU $FF80 ; $FF80->$FFFE

; *** MBC5 Equates ***

rRAMG        EQU $0000 ; $0000->$1fff
rROMB0       EQU $2000 ; $2000->$2fff
rROMB1       EQU $3000 ; $3000->$3fff
rRAMB        EQU $4000 ; $4000->$5fff


; --
; -- OAM flags
; --

OAMF_PRI   EQU %10000000 ; Priority
OAMF_YFLIP EQU %01000000 ; Y flip
OAMF_XFLIP EQU %00100000 ; X flip
OAMF_PAL0  EQU %00000000 ; Palette number; 0,1
OAMF_PAL1  EQU %00010000 ; Palette number; 0,1


;***************************************************************************
;*
;* Custom registers
;*
;***************************************************************************

; --
; -- P1 ($FF00)
; -- Register for reading joy pad info.    (R/W)
; --
rP1 EQU $FF00

P1F_5 EQU %00100000 ; P15 out port
P1F_4 EQU %00010000 ; P14 out port
P1F_3 EQU %00001000 ; P13 in port
P1F_2 EQU %00000100 ; P12 in port
P1F_1 EQU %00000010 ; P11 in port
P1F_0 EQU %00000001 ; P10 in port

; --
; -- SB ($FF01)
; -- Serial Transfer Data (R/W)
; --
rSB EQU $FF01

; --
; -- SC ($FF02)
; -- Serial I/O Control (R/W)
; --
rSC EQU $FF02

; --
; -- DIV ($FF04)
; -- Divider register (R/W)
; --
rDIV EQU $FF04


; --
; -- TIMA ($FF05)
; -- Timer counter (R/W)
; --
rTIMA EQU $FF05


; --
; -- TMA ($FF06)
; -- Timer modulo (R/W)
; --
rTMA EQU $FF06


; --
; -- TAC ($FF07)
; -- Timer control (R/W)
; --
rTAC EQU $FF07

TACF_START  EQU %00000100
TACF_STOP   EQU %00000000
TACF_4KHZ   EQU %00000000
TACF_16KHZ  EQU %00000011
TACF_65KHZ  EQU %00000010
TACF_262KHZ EQU %00000001

; --
; -- IF ($FF0F)
; -- Interrupt Flag (R/W)
; --
rIF EQU $FF0F

; --
; -- LCDC ($FF40)
; -- LCD Control (R/W)
; --
rLCDC EQU $FF40

LCDCF_OFF     EQU %00000000 ; LCD Control Operation
LCDCF_ON      EQU %10000000 ; LCD Control Operation
LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select
LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select
LCDCF_WINOFF  EQU %00000000 ; Window Display
LCDCF_WINON   EQU %00100000 ; Window Display
LCDCF_BG8800  EQU %00000000 ; BG & Window Tile Data Select
LCDCF_BG8000  EQU %00010000 ; BG & Window Tile Data Select
LCDCF_BG9800  EQU %00000000 ; BG Tile Map Display Select
LCDCF_BG9C00  EQU %00001000 ; BG Tile Map Display Select
LCDCF_OBJ8    EQU %00000000 ; OBJ Construction
LCDCF_OBJ16   EQU %00000100 ; OBJ Construction
LCDCF_OBJOFF  EQU %00000000 ; OBJ Display
LCDCF_OBJON   EQU %00000010 ; OBJ Display
LCDCF_BGOFF   EQU %00000000 ; BG Display
LCDCF_BGON    EQU %00000001 ; BG Display
; "Window Character Data Select" follows BG


; --
; -- STAT ($FF41)
; -- LCDC Status   (R/W)
; --
rSTAT EQU $FF41

STATF_LYC     EQU  %01000000 ; LYCEQULY Coincidence (Selectable)
STATF_MODE10  EQU  %00100000 ; Mode 10
STATF_MODE01  EQU  %00010000 ; Mode 01 (V-Blank)
STATF_MODE00  EQU  %00001000 ; Mode 00 (H-Blank)
STATF_LYCF    EQU  %00000100 ; Coincidence Flag
STATF_HB      EQU  %00000000 ; H-Blank
STATF_VB      EQU  %00000001 ; V-Blank
STATF_OAM     EQU  %00000010 ; OAM-RAM is used by system
STATF_LCD     EQU  %00000011 ; Both OAM and VRAM used by system
STATF_BUSY    EQU  %00000010 ; When set, VRAM access is unsafe


; --
; -- SCY ($FF42)
; -- Scroll Y (R/W)
; --
rSCY EQU $FF42


; --
; -- SCY ($FF43)
; -- Scroll X (R/W)
; --
rSCX EQU $FF43


; --
; -- LY ($FF44)
; -- LCDC Y-Coordinate (R)
; --
; -- Values range from 0->153. 144->153 is the VBlank period.
; --
rLY EQU $FF44


; --
; -- LYC ($FF45)
; -- LY Compare (R/W)
; --
; -- When LYEQUEQULYC, STATF_LYCF will be set in STAT
; --
rLYC EQU $FF45


; --
; -- DMA ($FF46)
; -- DMA Transfer and Start Address (W)
; --
rDMA EQU $FF46


; --
; -- BGP ($FF47)
; -- BG Palette Data (W)
; --
; -- Bit 7-6 - Intensity for %11
; -- Bit 5-4 - Intensity for %10
; -- Bit 3-2 - Intensity for %01
; -- Bit 1-0 - Intensity for %00
; --
rBGP EQU $FF47


; --
; -- OBP0 ($FF48)
; -- Object Palette 0 Data (W)
; --
; -- See BGP for info
; --
rOBP0 EQU $FF48


; --
; -- OBP1 ($FF49)
; -- Object Palette 1 Data (W)
; --
; -- See BGP for info
; --
rOBP1 EQU $FF49


; --
; -- WY ($FF4A)
; -- Window Y Position (R/W)
; --
; -- 0 <EQU WY <EQU 143
; --
rWY EQU $FF4A


; --
; -- WX ($FF4B)
; -- Window X Position (R/W)
; --
; -- 7 <EQU WX <EQU 166
; --
rWX EQU $FF4B


; --
; -- KEY 1 ($FF4D)
; -- Select CPU Speed (R/W)
; --
rKEY1 EQU $FF4D


; --
; -- VBK ($FF4F)
; -- Select Video RAM Bank (R/W)
; --
rVBK EQU $FF4F


; --
; -- HDMA1 ($FF51)
; -- Horizontal Blanking, General Purpose DMA (W)
; --
rHDMA1 EQU $FF51


; --
; -- HDMA2 ($FF52)
; -- Horizontal Blanking, General Purpose DMA (W)
; --
rHDMA2 EQU $FF52


; --
; -- HDMA3 ($FF53)
; -- Horizontal Blanking, General Purpose DMA (W)
; --
rHDMA3 EQU $FF53


; --
; -- HDMA4 ($FF54)
; -- Horizontal Blanking, General Purpose DMA (W)
; --
rHDMA4 EQU $FF54


; --
; -- HDMA5 ($FF55)
; -- Horizontal Blanking, General Purpose DMA (R/W)
; --
rHDMA5 EQU $FF55


; --
; -- RP ($FF56)
; -- Infrared Communications Port (R/W)
; --
rRP EQU $FF56


; --
; -- BCPS ($FF68)
; -- Background Color Palette Specification (R/W)
; --
rBCPS EQU $FF68


; --
; -- BCPD ($FF69)
; -- Background Color Palette Data (R/W)
; --
rBCPD EQU $FF69


; --
; -- BCPS ($FF6A)
; -- Object Color Palette Specification (R/W)
; --
rOCPS EQU $FF6A


; --
; -- BCPD ($FF6B)
; -- Object Color Palette Data (R/W)
; --
rOCPD EQU $FF6B


; --
; -- SVBK ($FF4F)
; -- Select Main RAM Bank (R/W)
; --
rSVBK EQU $FF70


; --
; -- IE ($FFFF)
; -- Interrupt Enable (R/W)
; --
rIE EQU $FFFF


IEF_HILO   EQU %00010000 ; Transition from High to Low of Pin number P10-P13
IEF_SERIAL EQU %00001000 ; Serial I/O transfer end
IEF_TIMER  EQU %00000100 ; Timer Overflow
IEF_LCDC   EQU %00000010 ; LCDC (see STAT)
IEF_VBLANK EQU %00000001 ; V-Blank




;***************************************************************************
;*
;* Sound control registers
;*
;***************************************************************************

; --
; -- AUDVOL/NR50 ($FF24)
; -- Channel control / ON-OFF / Volume (R/W)
; --
; -- Bit 7   - Vin->SO2 ON/OFF (Vin??)
; -- Bit 6-4 - SO2 output level (volume) (# 0-7)
; -- Bit 3   - Vin->SO1 ON/OFF (Vin??)
; -- Bit 2-0 - SO1 output level (volume) (# 0-7)
; --
rNR50 EQU $FF24
rAUDVOL EQU rNR50


; --
; -- AUDTERM/NR51 ($FF25)
; -- Selection of Sound output terminal (R/W)
; --
; -- Bit 7   - Output sound 4 to SO2 terminal
; -- Bit 6   - Output sound 3 to SO2 terminal
; -- Bit 5   - Output sound 2 to SO2 terminal
; -- Bit 4   - Output sound 1 to SO2 terminal
; -- Bit 3   - Output sound 4 to SO1 terminal
; -- Bit 2   - Output sound 3 to SO1 terminal
; -- Bit 1   - Output sound 2 to SO1 terminal
; -- Bit 0   - Output sound 0 to SO1 terminal
; --
rNR51 EQU $FF25
rAUDTERM EQU rNR51


; --
; -- AUDENA/NR52 ($FF26)
; -- Sound on/off (R/W)
; --
; -- Bit 7   - All sound on/off (sets all audio regs to 0!)
; -- Bit 3   - Sound 4 ON flag (doesn't work!)
; -- Bit 2   - Sound 3 ON flag (doesn't work!)
; -- Bit 1   - Sound 2 ON flag (doesn't work!)
; -- Bit 0   - Sound 1 ON flag (doesn't work!)
; --
rNR52 EQU $FF26
rAUDENA EQU rNR52


;***************************************************************************
;*
;* SoundChannel #1 registers
;*
;***************************************************************************

; --
; -- AUD1SWEEP/NR10 ($FF10)
; -- Sweep register (R/W)
; --
; -- Bit 6-4 - Sweep Time
; -- Bit 3   - Sweep Increase/Decrease
; --           0: Addition    (frequency increases???)
; --           1: Subtraction (frequency increases???)
; -- Bit 2-0 - Number of sweep shift (# 0-7)
; -- Sweep Time: (n*7.8ms)
; --
rNR10 EQU $FF10
rAUD1SWEEP EQU rNR10


; --
; -- AUD1LEN/NR11 ($FF11)
; -- Sound length/Wave pattern duty (R/W)
; --
; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%)
; -- Bit 5-0 - Sound length data (# 0-63)
; --
rNR11 EQU $FF11
rAUD1LEN EQU rNR11


; --
; -- AUD1ENV/NR12 ($FF12)
; -- Envelope (R/W)
; --
; -- Bit 7-4 - Initial value of envelope
; -- Bit 3   - Envelope UP/DOWN
; --           0: Decrease
; --           1: Range of increase
; -- Bit 2-0 - Number of envelope sweep (# 0-7)
; --
rNR12 EQU $FF12
rAUD1ENV EQU rNR12


; --
; -- AUD1LOW/NR13 ($FF13)
; -- Frequency lo (W)
; --
rNR13 EQU $FF13
rAUD1LOW EQU rNR13


; --
; -- AUD1HIGH/NR14 ($FF14)
; -- Frequency hi (W)
; --
; -- Bit 7   - Initial (when set, sound restarts)
; -- Bit 6   - Counter/consecutive selection
; -- Bit 2-0 - Frequency's higher 3 bits
; --
rNR14 EQU $FF14
rAUD1HIGH EQU rNR14


;***************************************************************************
;*
;* SoundChannel #2 registers
;*
;***************************************************************************

; --
; -- AUD2LEN/NR21 ($FF16)
; -- Sound Length; Wave Pattern Duty (R/W)
; --
; -- see AUD1LEN for info
; --
rNR21 EQU $FF16
rAUD2LEN EQU rNR21


; --
; -- AUD2ENV/NR22 ($FF17)
; -- Envelope (R/W)
; --
; -- see AUD1ENV for info
; --
rNR22 EQU $FF17
rAUD2ENV EQU rNR22


; --
; -- AUD2LOW/NR23 ($FF18)
; -- Frequency lo (W)
; --
rNR23 EQU $FF18
rAUD2LOW EQU rNR23


; --
; -- AUD2HIGH/NR24 ($FF19)
; -- Frequency hi (W)
; --
; -- see AUD1HIGH for info
; --
rNR24 EQU $FF19
rAUD2HIGH EQU rNR24


;***************************************************************************
;*
;* SoundChannel #3 registers
;*
;***************************************************************************

; --
; -- AUD3ENA/NR30 ($FF1A)
; -- Sound on/off (R/W)
; --
; -- Bit 7   - Sound ON/OFF (1EQUON,0EQUOFF)
; --
rNR30 EQU $FF1A
rAUD3ENA EQU rNR30


; --
; -- AUD3LEN/NR31 ($FF1B)
; -- Sound length (R/W)
; --
; -- Bit 7-0 - Sound length
; --
rNR31 EQU $FF1B
rAUD3LEN EQU rNR31


; --
; -- AUD3LEVEL/NR32 ($FF1C)
; -- Select output level
; --
; -- Bit 6-5 - Select output level
; --           00: 0/1 (mute)
; --           01: 1/1
; --           10: 1/2
; --           11: 1/4
; --
rNR32 EQU $FF1C
rAUD3LEVEL EQU rNR32


; --
; -- AUD3LOW/NR33 ($FF1D)
; -- Frequency lo (W)
; --
; -- see AUD1LOW for info
; --
rNR33 EQU $FF1D
rAUD3LOW EQU rNR33


; --
; -- AUD3HIGH/NR34 ($FF1E)
; -- Frequency hi (W)
; --
; -- see AUD1HIGH for info
; --
rNR34 EQU $FF1E
rAUD3HIGH EQU rNR34


; --
; -- AUD4LEN/NR41 ($FF20)
; -- Sound length (R/W)
; --
; -- Bit 5-0 - Sound length data (# 0-63)
; --
rNR41 EQU $FF20
rAUD4LEN EQU rNR41


; --
; -- AUD4ENV/NR42 ($FF21)
; -- Envelope (R/W)
; --
; -- see AUD1ENV for info
; --
rNR42 EQU $FF21
rAUD4ENV EQU rNR42


; --
; -- AUD4POLY/NR43 ($FF22)
; -- Polynomial counter (R/W)
; --
; -- Bit 7-4 - Selection of the shift clock frequency of the (scf)
; --           polynomial counter (0000-1101)
; --           freqEQUdrf*1/2^scf (not sure)
; -- Bit 3 -   Selection of the polynomial counter's step
; --           0: 15 steps
; --           1: 7 steps
; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf)
; --           000: f/4   001: f/8   010: f/16  011: f/24
; --           100: f/32  101: f/40  110: f/48  111: f/56  (fEQU4.194304 Mhz)
; --
rNR43 EQU $FF22
rAUD4POLY EQU rNR43


; --
; -- AUD4GO/NR44 ($FF23)
; -- (has wrong name and value (ff30) in Dr.Pan's doc!)
; --
; -- Bit 7 -   Inital
; -- Bit 6 -   Counter/consecutive selection
; --
rNR44 EQU $FF23
rAUD4GO EQU rNR44 ; silly name!

;***************************************************************************
;*
;* Cart related
;*
;***************************************************************************

CART_ROM                     EQU $00
CART_ROM_MBC1                EQU $01
CART_ROM_MBC1_RAM            EQU $02
CART_ROM_MBC1_RAM_BAT        EQU $03
CART_ROM_MBC2                EQU $05
CART_ROM_MBC2_BAT            EQU $06
CART_ROM_RAM                 EQU $08
CART_ROM_RAM_BAT             EQU $09
CART_ROM_MBC3_BAT_RTC        EQU $0F
CART_ROM_MBC3_RAM_BAT_RTC    EQU $10
CART_ROM_MBC3                EQU $11
CART_ROM_MBC3_RAM            EQU $12
CART_ROM_MBC3_RAM_BAT        EQU $13
CART_ROM_MBC5                EQU $19
CART_ROM_MBC5_BAT            EQU $1A
CART_ROM_MBC5_RAM_BAT        EQU $1B
CART_ROM_MBC5_RUMBLE         EQU $1C
CART_ROM_MBC5_RAM_RUMBLE     EQU $1D
CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E
CART_ROM_MBC7_RAM_BAT_GYRO   EQU $22
CART_ROM_POCKET_CAMERA       EQU $FC

CART_ROM_256K EQU 0
CART_ROM_512K EQU 1
CART_ROM_1M   EQU 2
CART_ROM_2M   EQU 3
CART_ROM_4M   EQU 4
CART_ROM_8M   EQU 5
CART_ROM_16M  EQU 6
CART_ROM_32M  EQU 7
CART_ROM_64M  EQU 8

CART_RAM_NONE EQU 0
CART_RAM_16K  EQU 1
CART_RAM_64K  EQU 2
CART_RAM_256K EQU 3

CART_RAM_ENABLE  EQU $0A
CART_RAM_DISABLE EQU $00

;***************************************************************************
;*
;* Keypad related
;*
;***************************************************************************

PADF_DOWN   EQU $80
PADF_UP     EQU $40
PADF_LEFT   EQU $20
PADF_RIGHT  EQU $10
PADF_START  EQU $08
PADF_SELECT EQU $04
PADF_B      EQU $02
PADF_A      EQU $01

PADB_DOWN   EQU $7
PADB_UP     EQU $6
PADB_LEFT   EQU $5
PADB_RIGHT  EQU $4
PADB_START  EQU $3
PADB_SELECT EQU $2
PADB_B      EQU $1
PADB_A      EQU $0

;***************************************************************************
;*
;* Screen related
;*
;***************************************************************************

SCRN_X    EQU 160 ; Width of screen in pixels
SCRN_Y    EQU 144 ; Height of screen in pixels
SCRN_X_B  EQU 20  ; Width of screen in bytes
SCRN_Y_B  EQU 18  ; Height of screen in bytes

SCRN_VX   EQU 256 ; Virtual width of screen in pixels
SCRN_VY   EQU 256 ; Virtual height of screen in pixels
SCRN_VX_B EQU 32  ; Virtual width of screen in bytes
SCRN_VY_B EQU 32  ; Virtual height of screen in bytes

;*
;* Nintendo scrolling logo
;* (Code won't work on a real GameBoy)
;* (if next lines are altered.)
NINTENDO_LOGO : MACRO
    DB  $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D
    DB  $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99
    DB  $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E
ENDM

    ENDC ;HARDWARE_INC

Pokun
Posts: 2714
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by Pokun »

Look out for the official GBC development documents it covers both GB and GBC.
There is also the good old pandocs.
Original Pandocs
Wiki version
Modern version

Great sumary of GB-dev


MBC5 is better for GBC since it supports the new GBC-exclusive high-speed mode. If you are fine with regular speed you can use MBC1 however.


You are using a mix of the old header and the new header. For a GBC game you must use the new header (in fact you can always use the new header even for DMG or SGB enhanced games) which means you can only use 11 characters for the title (you are using all 16). The 16th byte in the title is the CGB support code which should be set to either $80 or $C0 for GBC games:
$00 = DMG
$80 = DMG, CGB-enhanced
$C0 = CGB-exclusive

This is probably why your header is too large it must be exactly 80 bytes.
The 4 bytes between the title and the CGB support code is the game code which can be anything for homebrew as long as it is valid ASCII (valid characters are found in the official devdocs). Licensed games usually has a 3-letter code which is an abbreviation of the title and the final character is some sort of code, sometimes a region code like "J", "E" etc.

You also need to set "LICENSEE" (new maker code) to ASCII characters so "00" and not 0,0 as you have done now. Otherwise the header is using the old style and emulators might get confused. "00" is technically not valid for a licensed game but should be better than zeroes and as homebrewers we don't have much choice. I interpret "00" as "unlicensed game" so I always use it.

Finally "Manufacturer" (old maker code) in your code must be set to $33 not 0. This indicates that you are using the new header style which uses the SGB and CGB support codes.

For any header fields you are letting rgbfix handle, you must leave as zeroes or it will complain. But really the only thing you need rgbfix for is the checksum and the complement check fields ("-f hg" option for rgbfix). The rest can be done in the code. Since you are setting the GBC flag in your code there is no need to set it again in rgbfix with the -C or -c options.



There are a lot of new things you need to do for GBC and you have to check the above documents for that. But from the top of my head the GBC has 7 extra banks of RAM so you may want to clear them all instead of just bank 0.

Likewise LCD RAM (AKA VRAM) now has two banks so you may want to clear and initialize both. The place of the nametables in the second bank are the attributes for each nametable which includes things like palettes and flipping flags for BG tiles.
The second bank of the pattern tables is just an extra set of pattern tables so you may want to clear those too.

The system always boots in DMG mode so after basic DMG initialization you need to switch to GBC mode and high-speed mode (if using MBC5) and do further GBC initialization.
The official devdocs and pandocs both do a good job in covering all the new GBC registers you need to use for switching to these new banks and stuff. Most of the new GBC registers are for switching banks, color palettes, LCD RAM HDMA (similar to SNES) and for using the all-new IR-port. The APU is untouched (except for some new bugs introduced yay) and so are most of the other hardware like the window, BGs and sprites but some of the uses slightly different rules (sprite priority now depends on the sprite index number instead of the X-coordinate).

Oh and if you are making a GBC-exclusive game (CGB support code is set to $C0) you need to detect which system the player uses and if it's not a GBC or GBA you need to make a screen in DMG mode that tells the player that the game is GBC-exclusive then freeze the game or whatever. If GBC-enhanced (CGB support code $80) you also need to detect so that you can enable GBC mode only if the user is playing on a GBC/GBA.
Detecting is done by checking the accumulator right after boot. CPU registers B and C are also used for further detection:

Code: Select all

A = $01 - Game Boy (DMG) or Super Game Boy (SHVC-027)
A = $FF - Game Boy Pocket (MGB) or Super Game Boy 2 (SHVC-042)
A = $11 - Game Boy Color (CGB) or Game Boy Advance (AGB)
C = $13 - Game Boy (DMG) or Game Boy Pocket (MGB)
C = $14 - Super Game Boy (SHVC-027) or Super Game Boy 2 (SHVC-042)
C = $00 - Game Boy Color (CGB) or Game Boy Advance (AGB)
B = %xxxxxxx0 - Game Boy Color (CGB)
B = %xxxxxxx1 - Game Boy Advance (AGB)

In order to distinguish between a portable system and a SGB/SGB2, send the
SGB command MLT_REQ which enables multiple controllers on SGB and is ignored
by any non-SGB/SGB2 system.

B register is only good for telling apart a GBC from a GBA.
sdm
Posts: 424
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by sdm »

I made a few simple changes:
- HEADER change
- RGBFIX change, i.e. rgbfix -f hg
- I added the code for loading the palette using registers $FF68,$FF69 and $FF6A,$FF6B (2x 64 Bytes).

I made the values in PALETTE manually "by eye" because I couldn't find any GBC Pal editor.
I did not make changes to the second VRAM Bank where the NameTable attributes are.
Are there any map/screen editors, something like NES Screen Tool but for GBC?

I checked on Emulicious and BGB and they work, but I don't know if it will work on a real GBC.

Code: Select all


	DB "EXAMPLE",0,0,0,0,0,0,0,0	; Cart name - 15bytes
	DB $C0				; $143 - GBC_EXCLUSIVE
	DB 0,0				; $144 - Licensee code (not important)
	DB 0				; $146 - SGB Support indicator
	DB 1				; $147 - Cart type				; ROM_MBC1 EQU 1.
	DB 4				; $148 - ROM Size				; ROM_SIZE_512KBYTE EQU 4 / ROM_SIZE_512KBIT EQU 1 ???
	DB 0				; $149 - RAM Size				; RAM_SIZE_0KBIT EQU 0.
	DB 1				; $14a - Destination code
	DB $33				; $14b - Old licensee code
	DB 0				; $14c - Mask ROM version
	DB 0				; $14d - Complement check (important)
	DW 0				; $14e - Checksum (not important)

Code: Select all


@echo off

set name="demo"

set path=rgbds\

rgbasm -o %name%.o %name%.asm 
rgblink -o %name%.gbc %name%.o 
rgbfix -f hg %name%.gbc

echo Done.

del *.o

pause

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LoadBGRPalette:

	LD	A,0
	LD	[$FF4F],A					; Ustawienie Banku VRAM.

	LD	HL,BGRPalette					; 64 Bytes.

	LD	A,%10000000					; Set Bit 7 to auto-increment on write to rBGPD.
	LD	[$FF68],A					; rBGPI / $FF68 - BG Palette Byte Index (W).

	REPT	64						; Loop 64x.
	LD	A,[HL+]
	LD	[$FF69],A					; rBGPD / $FF69 - BG Palette Data (W).
	ENDR

	RET

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LoadSPRPalette:

	LD	A,0
	LD	[$FF4F],A					; Ustawienie Banku VRAM.

	LD	HL,SPRPalette					; 64 Bytes.

	LD	A,%10000000					; Set Bit 7 to auto-increment on write to rBGPD.
	LD	[$FF6A],A					; rOBPI / $FF6A - Object Palette Byte Index (W).

	REPT	64						; Loop 64x.
	LD	A,[HL+]
	LD	[$FF6B],A					; rOBPD / $FF6B - Object Palette Data (W).
	ENDR

	RET

Pokun wrote: Mon Apr 01, 2024 2:30 pm Oh and if you are making a GBC-exclusive game (CGB support code is set to $C0) you need to detect which system the player uses and if it's not a GBC or GBA you need to make a screen in DMG mode that tells the player that the game is GBC-exclusive then freeze the game or whatever. If GBC-enhanced (CGB support code $80) you also need to detect so that you can enable GBC mode only if the user is playing on a GBC/GBA.
Detecting is done by checking the accumulator right after boot. CPU registers B and C are also used for further detection:

Code: Select all

A = $01 - Game Boy (DMG) or Super Game Boy (SHVC-027)
A = $FF - Game Boy Pocket (MGB) or Super Game Boy 2 (SHVC-042)
A = $11 - Game Boy Color (CGB) or Game Boy Advance (AGB)
C = $13 - Game Boy (DMG) or Game Boy Pocket (MGB)
C = $14 - Super Game Boy (SHVC-027) or Super Game Boy 2 (SHVC-042)
C = $00 - Game Boy Color (CGB) or Game Boy Advance (AGB)
B = %xxxxxxx0 - Game Boy Color (CGB)
B = %xxxxxxx1 - Game Boy Advance (AGB)

In order to distinguish between a portable system and a SGB/SGB2, send the
SGB command MLT_REQ which enables multiple controllers on SGB and is ignored
by any non-SGB/SGB2 system.

B register is only good for telling apart a GBC from a GBA.
Is this required for the code to run on a real GBC? Will it only cause problems on a non-GBC console?

EDIT:

https://www.romhacking.net/utilities/1743/

I found the GBC palette editor, but I have no idea how it works - the effects are different in the editor and visible in the emulator.

Image
Attachments
test.gbc
(512 KiB) Downloaded 28 times
Pokun
Posts: 2714
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by Pokun »

sdm wrote: Tue Apr 02, 2024 10:29 am Are there any map/screen editors, something like NES Screen Tool but for GBC?
I'm not sure, I'm drawing everything using image editors like Graphics Gale and converts it to 2bpp CHR with RGBGFX (superfamiconv can also be used). I guess there might be some addon for general tile/map editors like Tiled but I haven't really looked around for these things in many years now. Check the links I included in my last post to see if there is anything useful there. The gbdev.gg8.se/forums may also be worth a look.


sdm wrote: Tue Apr 02, 2024 10:29 am I checked on Emulicious and BGB and they work, but I don't know if it will work on a real GBC.
The header is still not right.

Code: Select all

	DB "EXAMPLE",0,0,0,0      	; Cart name - 11 bytes
	DB "0000"			; $13F - Game Code
	DB $C0				; $143 - GBC_EXCLUSIVE
	DB "00"				; $144 - Licensee code (not important)
	DB 0				; $146 - SGB Support indicator
	DB 1				; $147 - Cart type				; ROM_MBC1 EQU 1.
	DB 4				; $148 - ROM Size				; ROM_SIZE_512KBYTE EQU 4 / ROM_SIZE_512KBIT EQU 1 ???
	DB 0				; $149 - RAM Size				; RAM_SIZE_0KBIT EQU 0.
	DB 1				; $14a - Destination code
	DB $33				; $14b - Old licensee code
	DB 0				; $14c - Mask ROM version
	DB 0				; $14d - Complement check (important)
	DW 0				; $14e - Checksum (not important)
There you go, Game Code and New Maker Code must be in ASCII or the header may not be considered valid.


sdm wrote: Tue Apr 02, 2024 10:29 am

Code: Select all

rgbasm -o %name%.o %name%.asm 
rgblink -o %name%.gbc %name%.o 
rgbfix -f hg %name%.gbc
You are not padding the ROM but the ROM size still got right. You may want to use the -p $FF option to pad with $FF with both RGBASM and RGBLINK. RGBFIX also accepts that option but there is no reason to pad again if you already padded with the assembler and linker.
$FF is better than 0 (which is default pad value for RGBDS) because crashes can be handled using RST $38 (which is the $FF opcode) and it's better for programming a PROM (since an empty PROM is all-$FF).
If padding with 0 (which is the NOP opcode) you will get NOP-slides into RAM and unpredictable crashes should the PC escape the code area due to some bug.


sdm wrote: Tue Apr 02, 2024 10:29 am
Pokun wrote: Mon Apr 01, 2024 2:30 pm you need to detect which system the player uses
Is this required for the code to run on a real GBC? Will it only cause problems on a non-GBC console?
It will run without doing this but it could potentially be dangerous to the hardware and save data (if using RAM+battery) if you just let it loose like that. The game will try to set CGB mode which does not exist on a DMG and will proceed to run the code which won't work correctly doing all sorts of unpredictable things.
Even if you don't want to bother with an error screen, you should probably at least freeze the game in an infinite loop with interrupts turned off if a pre-CGB system is detected to prevent the unpredictable.

Detecting CGB is very easy anyway, just save the accumulator in an unused register when clearing RAM then save it in a RAM register until you are ready for checking it (you need to wait for vblank and turn off LCD via $FF40). Then check it and if it's $11 it's a CGB or AGB, if not freeze the game.
Since it's CGB exclusive you don't need to check anything else.


sdm wrote: Tue Apr 02, 2024 10:29 am I found the GBC palette editor, but I have no idea how it works - the effects are different in the editor and visible in the emulator.
BGP (BG Palette) and OBP (Object Palette) are the monochrome palettes for DMG mode only and not used in CGB mode (though you can always initialize them).
BCP (BG Color Palette) and OCP (Object Color Palette) are the color palettes that are used in CGB mode.
Pandocs confuses the two types of palettes and calls them both BGP and OBP for some reason, it's pretty irritating.

That editor appears to display the color values in the same order they are stored in the palette memory, lowest byte first. So the color $7FFF (pure white) is written as FF7F in that editor. That's also the order you must write them in the BCPD and OCPD registers or you will get the color channels backwards.

The Color Palette memory looks like this (for both BG and OBJ):

Code: Select all


                              High byte  Low byte
Address    Color Palette No.   FEDCBA98 76543210   Palette Data No.
 LL  HH                       ___________________
$00~$01                    0 |Color H00|Color L00| 0
$02~$03                      |Color H01|Color L01| 1
$04~$05                      |Color H02|Color L02| 2
$06~$07                      |Color H03|Color L03| 3
                             |-------------------|
$08~$09                    1 |Color H10|Color L10| 0
$0A~$0B                      |Color H11|Color L11| 1
$0C~$0D                      |Color H12|Color L12| 2
$0E~$0F                      |Color H13|Color L13| 3
                             |-------------------|
$10~$37                  2~6 |        ...        |
                             |-------------------|
$38~$39                    7 |Color H70|Color L70| 0
$3A~$3B                      |Color H71|Color L71| 1
$3C~$3D                      |Color H72|Color L72| 2
$3E~$3F                      |Color H73|Color L73| 3
                             |___________________|
Each byte is individually addressed with the lower byte coming first. For example color palette 0 color 1 high byte has $03 as its address. The final
address is $3F which is color palette 7 color 3 high byte.

Read the pandocs (the modern one is most updated) about color compensation for LCD desaturation. Some emulators may have an option for this which makes colors look very different.


BTW that game is pretty cool and seems to work very well on Game Boy. :)
sdm
Posts: 424
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by sdm »

Thanks for correcting the header. :)

About accumulator detection:

Code: Select all


	SECTION	"Program Start",ROM0[$0150]

StartPoint:

	DI

	; Save the contents of the accumulator (A) as it was after turning on the console? And then check if he had $11 later? If it wasn't $11 suspend the code.


RGBFIX works with -p $ff but I don't see it converting 00 to FF in ROM.

However, RGBASM after adding -p $ff shows an error:

error: Invalid argument for option 'p'

I added an Attribute Map in the second VRAM Bank ($9800) to check the entire BGR palette.

I used the SNES program to edit the palette - I see that it has an option of 5 bits per color:
Attachments
jump.gbc
(128 KiB) Downloaded 29 times
snespaledit.png
Pokun
Posts: 2714
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by Pokun »

About detection, I mean it was an example, it depends on which order you are doing things. For example I detect the system something like this:

Code: Select all

  SECTION "RAM0_general",WRAM0[$C000]
sys_detect1:     DS 1   ;GB system (DMG/SGB: $01, MGB/SGB2: $FF, CGB/AGB: $11)
sys_detect2:     DS 1   ;GB system (DMG/MGB: $13, SGB/SGB2: $14, CGB/AGB: $00)
sys_detect3:     DS 1   ;GB system (CGB: %xxxxxxx0, AGB: %xxxxxxx1)

  SECTION "RAM0_stack",WRAM0[$CF80]
stack:           DS 128 ;reserved for stack

...

  SECTION "Header",ROM0[$0100]
; $0100 ~ $0103: Start Address
  di                 ;clear interrupt master flag
  jp start           ;continue init code past the header

  INCLUDE "gbheader.z80"

  SECTION "Start",ROM0[$0150]
start:

;Init Code:
  ld sp,stack+128    ;init stack pointer
  ld d,a             ;save A, used to detect Game Boy system
  
clear_ram:           ;clear internal work-RAM
  ld hl,$C000        ;RAM start address
.loop:
  ld a,$00           ;fill value: 0
  ld [hli],a
  ld a,h
  cp $DF
  jr nz,.loop
  ld a,l
  cp $FF             ;end of RAM: $DFFF
  jr nz,.loop
  ld a,$00
  ld [$DFFF],a       ;clear final RAM byte
  
  ld a,d
  ld [sys_detect1],a
  ld a,c
  ld [sys_detect2],a
  ld a,b
  ld [sys_detect3],a ;save system information in RAM
  
  call vblank_wait   ;wait for the vertical blanking interval

clear_mmio_registers:
  ld a,$00
  ldh [$FF40],a      ;clear LCD Control while in vblank (turns off LCD)
  ldh [$FF26],a      ;disable all sound (NR52)
  
  ...
  
;Subroutines:

vblank_wait :
  ldh a,[$FF44]
  cp $90
  jr nz,vblank_wait  ;if LY <> 144, then not in vblank yet, wait
  ret                ;else if LY = 144, in vblank, return
Here I save A in D, clear RAM and then put D back in A to save it in RAM register "sys_detect1 " for future use. I also save B and C in RAM but you don't need those unless you have a reason to check for the other systems as well.
I don't like to use things like subroutine calls before I've initialized stack which is why I clear RAM before waiting for vblank to turn off LCD, but the wait for LY = 144 could of course easily be done without a subroutine.

Anyway disabling interrupts, setting up stack (including clearing main RAM) and disabling the LCD are about the most minimal initialization that I can think of so after that you could run a routine that checks what the value in sys_detect1 is and run an infinite loop if it's not $11. Since interrupts and LCD are off it shouldn't go berserk and the screen would be empty. I also disabled sound which is good in case of a warm reset (like a soft-reset or Super Game Boy SNES hard-reset for example).



Oh yeah my bad, RGBASM may require the prefix 0x for hexadecimal numbers or just use decimal 255. Funny that RGBFIX accepts the $-sign.

Code: Select all

set outputfile=game
set sourcefile=main
set padvalue=0xFF

rem Assemble:
rgbasm -p %padvalue% -W no-obsolete -o %outputfile%.o %sourcefile%.z80

rem Link:
rgblink -p %padvalue% -m %outputfile%.map -n %outputfile%.sym ^
  -o %outputfile%.gb %outputfile%.o

rem Fix complement check and checksum:
rgbfix -f hg %outputfile%.gb
I use a variable in the batch script for the pad value so that both RGBASM and RGBLINK always uses the same pad value should I want to change it.

RGBFIX doesn't seem to do anything if you already padded the ROM using the assembler and linker. I think the -p option is just for people that like to pad any unused space left at the end of the ROM up to the desired size after building it, but that's moot if you used sections that lays out the entire ROM. The -p option for the assembler should pad any unused space between all sections with your chosen pad value and the -p option for the linker should use it when linking together the objects (I'm only using a single object file so I'm not sure linking is even required though). The -p option with RGBFIX probably only pads the end.
If my memory is right, I think it might be something left over from an older version of RGBDS which didn't support padding in the assembler. The modern version added many good things, but also some changes that I don't like (which is why I use the -W no-obsolete option).


Yeah the SNES and GBC both uses 15-bit RGB so many SNES color tools may be useful, although colors may not appear the same on a GBC LCD as on a TV. Many GBC games often uses more saturated colors to compensate for the mute shades of the display, which would make the game oversaturated on a TV if playing on a Game Boy Player via a Gamecube.
Also the 2bpp CHR dot pattern data format is the exact same one used with SNES which is different from the 2bpp format the NES uses, so many SNES CHR tools may be useful too.

Oh yeah I just saw that Superfamiconv specifically supports both GB and GBC and can do palettes, tilesets and maps.
sdm
Posts: 424
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by sdm »

Thanks, a lot has been explained about GBC :)

I changed the order in which TileMap and AttributeMap loaded. Previously Attributes were loaded last, which in GB Classic mode would overwrite $9800 causing background errors. Now I do it first and I see that when I run the game as GBC, it works with colors, and when I run the game in Classic mode, everything works fine (at least on an emulator like BGB, which allows you to switch between GB models).

Generally, I don't want to use any special capabilities of GBC, it would be nice to do something on GB Classic, but running on GBC it will have colors. :)
Attachments
game.gb
(128 KiB) Downloaded 27 times
Pokun
Posts: 2714
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by Pokun »

Congratulations!
Hmm I recently saw in my notes that the attribute table should be transferred to VRAM before the nametable but it didn't say why. But if it's in CGB mode it shouldn't matter which order?

OK so you want to make a DMG game with GBC enhancements, in that case set the CGB support code $80. You still need to detect the hardware of course so you can enable the colors only if a GBC is detected.
sdm
Posts: 424
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by sdm »

I don't really know what's best. I changed it because when I previously had Attributes after TileMap and ran the ROM in GB Classic (BGB) mode, I had errors in the background caused by the Attributes overwriting TileMap in $9800 (GB Classic did not switch the VRAM Bank because it does not have it). So I changed the order and it worked. It probably won't matter on GBC.

So I understand that setting GBC Flag $C0 will prevent the ROM from running on real GB Classic? And setting $80 will enable it and do I have to block copying the 128 Bytes Palette?

For now, I suggest using emulators, but this is probably wrong and it will be different on a real console?
tepples
Posts: 22718
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by tepples »

$C0 alone doesn't block running on pre-GBC systems. You still need to detect A != $11 and freeze on an error message.
calima
Posts: 1748
Joined: Tue Oct 06, 2015 10:16 am

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by calima »

In other words, the header flag is mainly for Nintendo to know which type of cart shell and box to include. They had different-shaped/colored shells for GB, GBC enhanced and GBC-only games, as well as box logos.
nitro2k01
Posts: 253
Joined: Sat Aug 28, 2010 9:01 am

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by nitro2k01 »

Pokun wrote: Mon Apr 01, 2024 2:30 pmYou are using a mix of the old header and the new header. For a GBC game you must use the new header (in fact you can always use the new header even for DMG or SGB enhanced games) which means you can only use 11 characters for the title (you are using all 16). The 16th byte in the title is the CGB support code which should be set to either $80 or $C0 for GBC games:
$00 = DMG
$80 = DMG, CGB-enhanced
$C0 = CGB-exclusive

This is probably why your header is too large it must be exactly 80 bytes.
The 4 bytes between the title and the CGB support code is the game code which can be anything for homebrew as long as it is valid ASCII (valid characters are found in the official devdocs). Licensed games usually has a 3-letter code which is an abbreviation of the title and the final character is some sort of code, sometimes a region code like "J", "E" etc.

You also need to set "LICENSEE" (new maker code) to ASCII characters so "00" and not 0,0 as you have done now. Otherwise the header is using the old style and emulators might get confused. "00" is technically not valid for a licensed game but should be better than zeroes and as homebrewers we don't have much choice. I interpret "00" as "unlicensed game" so I always use it.

Finally "Manufacturer" (old maker code) in your code must be set to $33 not 0. This indicates that you are using the new header style which uses the SGB and CGB support codes.
In terms of what you need to make your game work, this is mostly incorrect. The one and only thing you need to do to enable GBC features is to set bit 7 of the byte at address $0143, using values $80 or $C0. For GBC support, there's no need to set the the 4 byte code to valid characters, or the old licensee code code to $33. This might be needed for Nintendo approval, but none of us are sending our games to Nintendo for approval. Setting [$014B]=$33 is one of the requirements for SGB support, but not GBC support. I don't think any emulators are confused by incorrect data here either, but if you know any examples I'd be interested.
Pokun wrote: Mon Apr 01, 2024 2:30 pmFor any header fields you are letting rgbfix handle, you must leave as zeroes or it will complain. But really the only thing you need rgbfix for is the checksum and the complement check fields ("-f hg" option for rgbfix). The rest can be done in the code. Since you are setting the GBC flag in your code there is no need to set it again in rgbfix with the -C or -c options.
This is just my opinion, but generally speaking I think it's better to use rgbfix to set header fields, than setting the values in the source code. It's easy to make a mistake and offset the values (like the person asking the question did!) whereas rgbfix will always set the right values. Just set all of it to zeros in the source code and let rgbfix set the values you want.
Pokun wrote: Mon Apr 01, 2024 2:30 pmThe system always boots in DMG mode so after basic DMG initialization you need to switch to GBC mode and high-speed mode (if using MBC5) and do further GBC initialization.
This is kind of a misleading statement. A GBC won't boot into and DMG mode, and then you can switch between the modes. The boot ROM reads the header and either boots into DMG or GBC mode, which are different, and can't be changed after the game is booted into either one. In DMG mode, all enhancement are of course locked out. In GBC mode, some things are different/locked out too. BGP, OBP0 and OBP1 (the DMG palette registers) have no effects, and some of the bits in LCDC have a different meaning. Meaning, if you try to run a DMG game in GBC mode by modifying the byte at $0143, it generally won't work §00% correctly. Even if you set the GBC palette once, any changes the game tries make to the palette (using BGP, OBP0/1) will be ignored.
Pokun
Posts: 2714
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by Pokun »

1)
Yes I know the boot-ROM doesn't care about most things in the header, that's not part of my concerns. I just told him what needs to be done for it to be a correctly formatted new-style header (well mostly, the "00" maker code is not on Nintendo's list but I don't have any better suggestions) so that it doesn't cause potential confusion in the future.
I don't care if no emulator, flashcart or other tool that exists now relies on this or that. One may always be created in the future so it's best to just get these things right from the beginning and be done with it. The header is an easy way to communicate this metadata to such tools, and creating a new header standard when we already have the one set by Nintendo, makes little sense to me.


2)
Yeah I know some people prefer to use RGBFIX to make the header for them. It might be easier to change some options in the build script instead of in the source in some cases if you are building different versions of the game for example. But it could also be achieved with assembly-time constants in the source.
I don't know, I personally prefer to do the header in the source as much as possible and use constants or macro to make them easy to change. I always check with hex editors, emulators and other tools to make sure I get it right.


3)
I see, I guess I was wrong. I think I confused CGB mode with high-speed mode which must be set manually if it is to be used and which can also be switched back to normal-speed mode.



BTW I read that you can get away with high-speed mode on pre-MBC5 mappers as long as you don't use it when switching banks, and of course mapper-less cartridges are also high-speed mode compatible.
sdm
Posts: 424
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by sdm »

I ran the ROM on GBC and GBP and it works fine. But I don't know about a real MBC1 card because I ran it using a cheap everdrive clone.
Attachments
IMG_20240406_104553.jpg
IMG_20240406_104907.jpg
Pokun
Posts: 2714
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Changing the Init code from GB Classic to GB Color (RGBASM)

Post by Pokun »

sdm wrote: Tue Apr 02, 2024 10:29 am I made the values in PALETTE manually "by eye" because I couldn't find any GBC Pal editor.
I did not make changes to the second VRAM Bank where the NameTable attributes are.
Are there any map/screen editors, something like NES Screen Tool but for GBC?
I checked my computer and found a few tools that I had but haven't really used. They can be found at Jeff Frohwein's old GB dev site which is amazingly still around.

Gameboy Tile Designer
Gameboy Map Builder


sdm wrote: Mon Apr 01, 2024 10:41 am

Code: Select all

	HALT							; the assembler seems to be auto adding a nop
	NOP
Oh yeah the original RGBDS and the later fork by Otakuzoku does indeed put NOPs automatically after HALT instructions unless you use the -h option with the assembler, in which case you have to manually insert a NOP after a HALT (the reason is because of a hardware bug that makes the instruction directly after HALT not always be executed). Likewise it automatically changes LD instructions for LDH whenever it operates within the high-memory range unless you use the -L option if you prefer to manually specify LDH instructions.
However, if you are using the modern fork (which has tons of fixes) these two options are reversed so that the assembler does not babysit you by default and the options activates the babysit functions instead of deactivating them. I prefer this new way better, even if it meant that I had to modify my build script.
Post Reply