; Hello World
; John Harrison
; With lots o' code borrowed from all over the place
; some tutorial-like comments stolen from "hello world" by GABY

; VERSIONS
; 1.01 02/09/07
;   fixed typos and clarified a few things in the comments
; 1.00 02/02/07

; Most GameBoy assemblers (and most other assembly
; language assemblers) use a semicolon to indicate
; that everything following it on a particular line
; is to be ignored and be treated purely as comments
; rather than code.

; gbhw.inc contains the
; 'Hardware Defines' for our program. This has
; address location labels for all of the GameBoy
; Hardware I/O registers. We can 'insert' this file
; into the present EXAMPLE1.ASM file by using the
; assembler INCLUDE command:

INCLUDE "gbhw.inc" ; standard hardware definitions from devrs.com

;  Next we want to include a file that contains a font
; macro. A macro is a portion of code or data that
; gets 'inserted' into your program. At this point,
; we are not actually inserting anything but a macro
; definition into our file. Code or data isn't physically
; inserted into a program until you invoke a macro which
; we will do later. For now, we are just making the macro
; name recognizable by our program.

INCLUDE "ibmpc1.inc" ; ASCII character set from devrs.com

; We are going to keep interrupts disabled for this program.
; However, it is good practice to leave the reserved memory locations for interrupts with
; executable code. It make for a nice template as well to fill in code when we use interrupts
; in the future
SECTION	"Vblank",HOME[$0040]
	reti
SECTION	"LCDC",HOME[$0048]
	reti
SECTION	"Timer_Overflow",HOME[$0050]
	reti
SECTION	"Serial",HOME[$0058]
	reti
SECTION	"p1thru4",HOME[$0060]
	reti

;  Next we need to include the standard GameBoy ROM header
; information that goes at location $0100 in the ROM. (The
; $ before a number indicates that the number is a hex value.)
;
;  ROM location $0100 is also the code execution starting point
; for user written programs. The standard first two commands
; are usually always a NOP (NO Operation) and then a JP (Jump)
; command. This JP command should 'jump' to the start of user
; code. It jumps over the ROM header information as well that
; is located at $104.
;
;  First, we indicate that the following code & data should
; start at address $100 by using the following SECTION assembler
; command:

SECTION	"start",HOME[$0100]
nop
jp	begin

;  To include the standard ROM header information we
; can just use the macro ROM_HEADER. We defined this macro
; earlier when we INCLUDEd "gbhw.inc".
;
;  The ROM_NOMBC just suggests to the complier that we are
; not using a Memory Bank Controller because we don't need one
; since our ROM won't be larger than 32K bytes.
;
;  Next we indicate the cart ROM size and then the cart RAM size.
; We don't need any cart RAM for this program so we set this to 0K.

; ****************************************************************************************
; ROM HEADER and ASCII character set
; ****************************************************************************************
; ROM header
	ROM_HEADER	ROM_NOMBC, ROM_SIZE_32KBYTE, RAM_SIZE_0KBYTE

; Next we need to include some code for doing
; RAM copy, RAM fill, etc.
INCLUDE "memory.asm"

;  Next, let's actually include font tile data into the ROM
; that we are building. We do this by invoking the chr_IBMPC1
; macro that was defined earlier when we INCLUDEd "ibmpc1.inc".
;
;  The 1 & 8 parameters define that we want to include the
; whole IBM-PC font set and not just parts of it.
;
;  Right before invoking this macro we define the label
; TileData. Whenever a label is defined with a colon; it is given the value of the current ROM location.
;  As a result, TileData now has a memory location value that
; is the same as the first byte of the font data that we are
; including. We shall use the label TileData as a "handle" or
; "reference" for locating our font data.

TileData:
	chr_IBMPC1	1,8 ; LOAD ENTIRE CHARACTER SET

;  The NOP and then JP located at $100 in ROM are executed
; which causes the the following code to be executed next.

; ****************************************************************************************
; Main code Initialization:
; set the stack pointer, enable interrupts, set the palette, set the screen relative to the window
; copy the ASCII character table, clear the screen
; ****************************************************************************************
begin:
; First, it's a good idea to Disable Interrupts
; using the following command. We won't be using
; interrupts in this example so we can leave them off.

	di

;  Next, we should initialize our stack pointer. The
; stack pointer holds return addresses (among other things)
; when we use the CALL command so the stack is important to us.
;
;  The CALL command is similar to executing
; a procedure in the C & PASCAL languages.
;
; We shall set the stack to the top of high ram + 1.
;
	ld	sp, $ffff		; set the stack pointer to highest mem location we can use + 1

;  Here we are going to setup the background tile
; palette so that the tiles appear in the proper
; shades of grey.
;
;  To do this, we need to write the value %11100100 to the
; memory location $ff47. In the 'gbhw.inc' file we
; INCLUDEd there is a definition that rBGP=$ff47 so
; we can use the rGBP label to do this
;
;  The first instruction loads the value %11100100 into the
; 8-bit register A and the second instruction writes
; the value of register A to memory location $ff47.

init:
	ld	a, %11100100 	; Window palette colors, from darkest to lightest
	ld	[rBGP], a		; CLEAR THE SCREEN

;  Here we are setting the X/Y scroll registers
; for the tile background to 0 so that we can see
; the upper left corner of the tile background.
;
;  Think of the tile background RAM (which we usually call
; the tile map RAM) as a large canvas. We draw on this
; 'canvas' using 'paints' which consist of tiles and
; sprites (we will cover sprites in another example.)
;
;  We set the scroll registers to 0 so that we can
; view the upper left corner of the 'canvas'.

	ld	a,0			; SET SCREEN TO TO UPPER RIGHT HAND CORNER
	ld	[rSCX], a
	ld	[rSCY], a

;  Next we shall turn the Liquid Crystal Display (LCD)
; off so that we can copy data to video RAM. We can
; copy data to video RAM while the LCD is on but it
; is a little more difficult to do and takes a little
; bit longer. Video RAM is not always available for
; reading or writing when the LCD is on so it is
; easier to write to video RAM with the screen off.
;
;  To turn off the LCD we do a CALL to the StopLCD
; subroutine at the bottom of this file. The reason
; we use a subroutine is because it takes more than
; just writing to a memory location to turn the
; LCD display off. The LCD display should be in
; Vertical Blank (or VBlank) before we turn the display
; off. Weird effects can occur if you don't wait until
; VBlank to do this and code written for the Super
; GameBoy won't work sometimes you try to turn off
; the LCD outside of VBlank.

	call	StopLCD		; YOU CAN NOT LOAD $8000 WITH LCD ON
	
;  In order to display any text on our 'canvas'
; we must have tiles which resemble letters that
; we can use for 'painting'. In order to setup
; tile memory we will need to copy our font data
; to tile memory using the routine 'mem_CopyMono'
; found in the 'memory.asm' library we INCLUDEd
; earlier.
;
;  For the purposes of the 'mem_CopyMono' routine,
; the 16-bit HL register is used as a source memory
; location, DE is used as a destination memory location,
; and BC is used as a data length indicator.

	ld	hl, TileData
	ld	de, _VRAM		; $8000
	ld	bc, 8*256 		; the ASCII character set: 256 characters, each with 8 bytes of display data
	call	mem_CopyMono	; load tile data
	
; We turn the LCD on. Parameters are explained in the I/O registers section of The GameBoy reference under I/O register LCDC
	ld	a, LCDCF_ON|LCDCF_BG8000|LCDCF_BG9800|LCDCF_BGON|LCDCF_OBJ16|LCDCF_OBJOFF 
	ld	[rLCDC], a	
	
; Next, we clear our 'canvas' to all white by
; 'setting' the canvas to ascii character $20
; which is a white space.

	ld	a, 32		; ASCII FOR BLANK SPACE
	ld	hl, _SCRN0
	ld	bc, SCRN_VX_B * SCRN_VY_B
	call	mem_SetVRAM

	
; ****************************************************************************************
; Main code:
; Print a character string in the middle of the screen
; ****************************************************************************************
; Now we need to paint the message
; " Hello World !" onto our 'canvas'. We do this with
; one final memory copy routine call.

	ld	hl,Title
	ld	de, _SCRN0+3+(SCRN_VY_B*7) ; 
	ld	bc, TitleEnd-Title
	call	mem_CopyVRAM
	
; ****************************************************************************************
; Prologue
; Wait patiently 'til somebody kills you
; ****************************************************************************************
; Since we have accomplished our goal, we now have nothing
; else to do. As a result, we just Jump to a label that
; causes an infinite loop condition to occur.
wait:
	halt
	nop
	jr	wait
	
; ****************************************************************************************
; hard-coded data
; ****************************************************************************************
Title:
	DB	"Hello World !"
TitleEnd:

; ****************************************************************************************
; StopLCD:
; turn off LCD if it is on
; and wait until the LCD is off
; ****************************************************************************************
StopLCD:
        ld      a,[rLCDC]
        rlca                    ; Put the high bit of LCDC into the Carry flag
        ret     nc              ; Screen is off already. Exit.

; Loop until we are in VBlank

.wait:
        ld      a,[rLY]
        cp      145             ; Is display on scan line 145 yet?
        jr      nz,.wait        ; no, keep waiting

; Turn off the LCD

        ld      a,[rLCDC]
        res     7,a             ; Reset bit 7 of LCDC
        ld      [rLCDC],a

        ret
