Commits

Justin Lloyd committed 7700109

First commit of project

Comments (0)

Files changed (41)

+syntax: glob
+*.suo
+*.pdb
+*.log
+*.bak
+md backup
+copy *.S .\backup
+copy *.I .\backup
+copy *.asm .\backup
+copy *.bat .\backup
+copy *.inc .\backup
+copy *.z80 .\backup
+copy *.lik .\backup
+copy *.mk .\backup
+copy *.c .\backup
+copy *.h .\backup
+copy *.txt .\backup
+copy *.doc .\backup
+					IF		!DEF(__BANKS_I__)
+__BANKS_I__			SET		1
+					INCLUDE	"Conditional.i"
+
+k_BANK_NUMBER			EQU		$7FFF								; address where current bank # can be found
+
+						RSSET	0
+k_BANK_GAME				RB		1									; bank #0
+k_BK_LAST				RB		0									; bank #1 -- last bank # used, must be at end of list
+
+
+;********************************************************************
+; NAME: FT_INTR (macro)												*
+; AUTH:	JLloyd -- 99/04/01											*
+;																	*
+; This macro sets the section in the assembler to that used by		*
+; interrupt routines.												*
+;																	*
+;********************************************************************
+
+FT_INTR:			MACRO
+					SECTION	"INTR\@",HOME
+					ENDM
+
+
+;********************************************************************
+; NAME: FT_GAME (macro)												*
+; AUTH:	JLloyd -- 99/04/01											*
+;																	*
+; This macro sets the section in the assembler to that used by		*
+; utility routines.													*
+;																	*
+;********************************************************************
+
+FT_GAME:			MACRO
+					SECTION	"GAME\@",HOME
+					ENDM
+
+;********************************************************************
+; NAME: DT_VARS (macro)												*
+; AUTH:	JLloyd -- 99/04/01											*
+;																	*
+; This macro sets the section in the assembler to that used by		*
+; global variables.													*
+;																	*
+;********************************************************************
+DT_VARS:			MACRO
+					SECTION	"VARS\@",BSS
+					ENDM
+
+;********************************************************************
+; NAME: DT_DATA (macro)												*
+; AUTH:	JLloyd -- 99/04/01											*
+;																	*
+; This macro sets the section in the assembler to that used by		*
+; regular data.														*
+;																	*
+;********************************************************************
+DT_DATA:			MACRO
+					SECTION	"DATA\@",HOME
+					ENDM
+
+					ENDC
+					INCLUDE	"Banks.i"
+
+
+;********************************************************************
+; NAME:	Not Applicable												*
+;																	*
+; This brief and weird piece of code places a single byte that		*
+; contains the current bank # at ROM address $7FFF in ever ROM bank	*
+; above 0 (1 through to last bank). The value can then be read out	*
+; and the current ROM bank # determined easily.						*
+;																	*
+; This code is redundant if the latest version of XLINK is used.	*
+;																	*
+;********************************************************************
+
+;bankCount			SET		1
+;					REPT	k_BK_LAST
+;					SECTION "BankNum\@",DATA[$7FFF],BANK[bankCount]
+;					DB		bankCount
+;bankCount = bankCount + 1
+;					ENDR
+;					PURGE	bankCount
+					INCLUDE	"Conditional.i"
+
+;********************************************************************
+;																	*
+; Verify that conditional version is current.						*
+;																	*
+;********************************************************************
+
+					IF		DEF(k_BLDOPT_CONDITIONAL_VERSION)
+						IF		k_BLDOPT_CONDITIONAL_VERSION<0001251
+							FAIL	"CONDITIONAL.I is out of date. Retrieve the latest version from VSS.\n"
+						ENDC
+					ELSE
+						FAIL	"CONDITIONAL.I is out of date. Retrieve the latest version from VSS.\n"
+					ENDC
+
+;********************************************************************
+;																	*
+; Display some debugging messages for the build options.			*
+;																	*
+;********************************************************************
+					PRINTT	"\n\n\n********************************************************************\n"
+					PRINTT	"LinkUp conditional build options\n\n"
+					PRINTT	"********************************************************************\n\n\n\n"
+					IF		!DEF(__COPYDATA_I__)
+__COPYDATA_I__		SET		1
+
+					GLOBAL	MemCopyBig
+					ENDC
+					INCLUDE	"standard.i"
+
+	
+;********************************************************************
+;																	*
+; NAME:	MemCopyBig													*
+; I/P:		HL	-- -> source addr									*
+;			BC	-- -> destination addr								*
+;			DE	-- length of data to copy							*
+;																	*
+; This function copies a block of memory from the specified source	*
+; to the specified destination address. It takes three parameters,	*
+; a data source address, a data destination address, and the length *
+; of the data block to copy. It does not check for overlapping		*
+; regions of memory.												*
+;																	*
+;********************************************************************
+					FT_GAME
+MemCopyBig:			PUSHALL											; preserve registers
+.CopyData:			LD		A,[HL+]									; pick up next source byte
+					LD		[BC],A									; store at next destination location
+					INC		BC										; increment destination pointer
+					DEC		DE										; decrement length counter
+					LD		A,E										; get lsb of length remaining
+					OR		D										; combine with msb of length remaining
+					JR		NZ,.CopyData							; zero length? no, so copy another byte
+					POPALL											; restore registers
+					RET												; exit function
+					IF		!DEF(__FONT_I__)
+__FONT_I__			SET		1
+
+					GLOBAL	PrintChar
+					GLOBAL	PrintString
+					GLOBAL	InitFont
+					GLOBAL	NewLine
+					GLOBAL	CursorHome
+
+					GLOBAL	PrintCol
+					GLOBAL	PrintRow
+
+					ENDC
+					INCLUDE	"Banks.i"
+					INCLUDE	"Font.i"
+					INCLUDE	"FontData.i"
+					INCLUDE "Hardware.i"
+					INCLUDE "Utility.i"
+					INCLUDE "Shift.i"
+
+k_NEWLINE			EQU		$0D										; ASCII code to output a new line
+k_CURSOR_HOME		EQU		$0C										; ASCII code to move cursor to top-left of screen
+k_CURSOR_RIGHT		EQU		$01										; non-ASCII code to move cursor right one column
+
+k_FONT_ATTRIB		EQU		$00										; attribute to use when printing
+k_FONT_BASE			EQU		$00										; base tile # to add to character #
+k_FONT_VRAM			EQU		$80										; vram address to place font data at
+k_FONT_BANK			EQU		0										; vram bank # to place font data at
+
+;********************************************************************
+;																	*
+; Local Module Variables											*
+;																	*
+;********************************************************************
+					DT_VARS
+PrintCol:			DS	1											; current column to print at
+PrintRow:			DS	1											; current row to print at
+
+
+;********************************************************************
+; NAME:	InitFont													*
+;																	*
+; This function initialises the font system. It loads the font tile	*
+; set to the VRAM, and places the cursor at the top-left corner of	*
+; the screen.														*
+;																	*
+;********************************************************************
+					FT_GAME
+InitFont:			IF k_FONT_BANK==0
+					VRAMBANK	0									; select vram bank #0
+					ELSE
+					VRAMBANK	1									; select vram bank #1
+					ENDC
+					LD		E,k_FONT_BASE							; tile # to place font data at
+					LD		D,37									; # tiles to load
+					LD		A,k_FONT_VRAM							; -> vram address to load font data to
+					LD		BC,FontData								; -> font data
+					CALL	LoadTileData							; load font tiles to vram
+					CALL	CursorHome								; place cursor at top-left of screen
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	CursorHome													*
+;																	*
+; This function moves the cursor to the top-left corner of the		*
+; screen.															*
+;																	*
+;********************************************************************
+					FT_GAME
+CursorHome:			PUSH	AF										; preserve register
+					XOR		A										; clear column & row
+					LD		[PrintCol],A							; set column to zero
+					LD		[PrintRow],A							; set row to zero
+					POP		AF										; restore register
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	CursorRight													*
+;																	*
+; This function moves the cursor right by one character. It wraps	*
+; the column around the screen if it reaches the right-hand edge.	*
+;																	*
+;********************************************************************
+					FT_GAME
+CursorRight:		PUSH	AF										; preserve register
+					LD		A,[PrintCol]							; pick up current column #
+					INC		A										; increment column #
+					AND		$1F										; ensure that column # stays on screen
+					LD		[PrintCol],A							; store new value of column #
+					POP		AF										; restore register
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	PrintString													*
+; I/P:	HL	--	-> null-terminated string							*
+;																	*
+; This function prints a string to the screen at the current cursor	*
+; position. It does not handle screen wrap. It interprets new line	*
+; and cursor movement if it is in the string.						*
+;																	*
+;********************************************************************
+					FT_GAME
+PrintString:		PUSH	HL										; preserve register
+					PUSH	AF										; preserve register
+.Print:				LD		A,[HL+]									; pick up next character to print
+				; null terminator?
+					OR		A										; test character code
+					JR		Z,.Exit									; is current character == NULL? yes, so end of string, exit function
+				; new line command?
+					CP		k_NEWLINE								; is current character == CR?
+					JR		NE,.NotNewline							; no, so try a different character
+					CALL	NewLine									; move cursor to new line
+					JR		.Print									; print next character
+				; cursor home command?
+.NotNewline:		CP		k_CURSOR_HOME							; is current character == CLS?
+					JR		NE,.NotHome								; no, so try a different character
+					CALL	CursorHome								; move cursor to home position
+					JR		.Print									; print next character
+				; cursor right command?
+.NotHome:			CP		k_CURSOR_RIGHT							; is current character == CURSOR RIGHT?
+					JR		NE,.NotCursorRight						; no, so try a different character
+					CALL	CursorRight								; move cursor one character space right
+					JR		.Print									; print next character
+				; output characters
+.NotCursorRight:	CALL	PrintChar								; display current character
+					JR		.Print									; print next character
+.Exit:				POP		AF										; restore register
+					POP		HL										; restore register
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	PrintChar													*
+; I/P:	A	-- ASCII code of character to display					*
+;																	*
+; This function prints a character on the screen. It takes a single	*
+; parameter that is the character to be printed. The character must	*
+; be one of the printable characters between ASCII code 32 and 126.	*
+; The correct VRAM address is calculated from the cursor column &	*
+; row.																*
+;																	*
+;********************************************************************
+					FT_GAME
+PrintChar:			PUSHALL											; preserve registers
+				; translate ASCII char to local font
+					LD		C,A										; get character to display
+					LD		B,0										; set msb of character offset
+					LD		HL,CharLookup							; -> character translation table
+					ADD		HL,BC									; add character to display
+					LD		C,[HL]									; pick up character tile #
+				; calculate VRAM address
+					LD		A,[PrintRow]							; pick up current row # of cursor
+					LD		E,A										; set lsb of vram address
+					LD		D,0										; set msb of vram address
+					SLA16	DE,5									; * 32 to get vram row
+					LD		A,[PrintCol]							; pick up current col # of cursor
+					ADD		E										; add lsb of vram row
+					LD		E,A										; set new lsb of vram address
+					LD		A,0										; set msb of current col #
+					ADC		D										; add msb of vram row
+					LD		D,A										; set new msb of vram address
+					LD		HL,k_VRAM_BG_LOW						; -> vram background
+					ADD		HL,DE									; add calculated vram offset
+				; set tile attribute
+					VRAMBANK	1									; switch to vram bank #1
+.SetPalette1:		WaitForVRAM										; wait for vram access
+					LD		[HL],k_FONT_ATTRIB						; set vram tile attribute
+				; set tile index
+					VRAMBANK	0									; switch to vram bank #0
+.SetPalette2:		WaitForVRAM										; wait for vram access
+					LD		A,C										; get character code
+					ADD		k_FONT_BASE								; add base tile # of font data
+					LD		[HL],A									; place tile # into vram
+					CALL	CursorRight								; move cursor right one character place
+					POPALL											; restore registers
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	GotoXY														*
+; I/P:	B	-- column number to move cursor to						*
+;		C	-- row number to move cursor to							*
+;																	*
+; This function moves the cursor the specified column & row number.	*
+; It takes two parameters, the column number and row number of the	*
+; new cursor position. Range checking is performed to ensure that	*
+; the values remain in the VRAM region.								*
+;																	*
+;********************************************************************
+					FT_GAME
+GotoXY:				PUSH	AF										; preserve register
+					LD		A,B										; get specified column #
+					AND		$1F										; make sure it stays in range
+					LD		[PrintCol],A							; store new column #
+					LD		A,C										; get row #
+					AND		$1F										; make sure it stays in range
+					LD		[PrintRow],A							; store new row #
+					POP		AF										; restore register
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	NewLine														*
+;																	*
+; This function moves the cursor to the beginning of the next row.	*
+; It ensures that the row wraps around correctly on the screen.		*
+;																	*
+;********************************************************************
+					FT_GAME
+NewLine:			PUSH	AF										; preserve register
+					XOR		A										; set zero value for col #
+					LD		[PrintCol],A							; store new col #
+					LD		A,[PrintRow]							; pick up row #
+					INC		A										; increment row #
+					AND		$1F										; make sure row # wraps around on vram
+					LD		[PrintRow],A							; store new row #
+					POP		AF										; restore register
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	LineFeed													*
+;																	*
+; This function outputs a line feed. It moves the row that the next	*
+; character will be displayed at down, one screen row. If the edge	*
+; of the screen is reached, it will wrap around to the top of the	*
+; screen.															*
+;																	*
+;********************************************************************
+					FT_GAME
+LineFeed:			PUSH	AF										; preserve register
+					LD		A,[PrintRow]							; pick up current row #
+					INC		A										; move down one row
+					AND		$1F										; make sure row # wraps around on vram
+					LD		[PrintRow],A							; store new row #
+					POP		AF										; restore register
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	CarriageReturn												*
+;																	*
+; This function outputs a carriage return. It moves the column that	*
+; the next character will be displayed at, to the far left-hand		*
+; side of the screen.												*
+;																	*
+;********************************************************************
+					FT_GAME
+CarriageReturn:		PUSH	AF										; preserve register
+					XOR		A										; set zero value for col #
+					LD		[PrintCol],A							; store new column #
+					POP		AF										; restore register
+					RET												; exit function
+					IF		!DEF(__FONTDATA_I__)
+__FONTDATA_I__		SET		1
+
+					GLOBAL	FontData
+					GLOBAL	CharLookup
+
+					ENDC
+					INCLUDE	"Banks.i"
+					INCLUDE	"FontData.i"
+
+					SECTION "FontData",DATA
+CharLookup:			DB		 0,  0,  0,  0,  0,  0,  0,  0			;   0 -   7
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			;   8 -  15
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			;  16 -  23
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			;  24 -  31
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			;  32 -  39
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			;  40 -  47
+					DB		 1,  2,  3,  4,  5,  6,  7,  8			;  48 -  55
+					DB		 9, 10,  0,  0,  0,  0,  0,  0			;  56 -  63
+					DB		 0, 11, 12, 13, 14, 15, 16, 17			;  64 -  71
+					DB		18, 19, 20, 21, 22, 23, 24, 25			;  72 -  79
+					DB		26, 27, 28, 29, 30, 31, 32, 33			;  80 -  87
+					DB		34, 35, 36,  0,  0,  0,  0,  0			;  88 -  95
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			;  96 - 103
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			; 104 - 111
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			; 112 - 119
+					DB		 0,  0,  0,  0,  0,  0,  0,  0			; 120 - 127
+FontData:
+ChSpace:			DB		$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00				;'  '
+ChNum0:				DB		$3c,$3c,$66,$66,$6e,$6e,$76,$76,$66,$66,$66,$66,$3c,$3c,$00,$00				;' 0'
+ChNum1:				DB		$18,$18,$38,$38,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$00,$00				;' 1'
+ChNum2:				DB		$3c,$3c,$66,$66,$0e,$0e,$1c,$1c,$38,$38,$70,$70,$7e,$7e,$00,$00				;' 2'
+ChNum3:				DB		$7e,$7e,$0c,$0c,$18,$18,$3c,$3c,$06,$06,$46,$46,$3c,$3c,$00,$00				;' 3'
+ChNum4:				DB		$0c,$0c,$1c,$1c,$2c,$2c,$4c,$4c,$7e,$7e,$0c,$0c,$0c,$0c,$00,$00				;' 4'
+ChNum5:				DB		$7e,$7e,$60,$60,$7c,$7c,$06,$06,$06,$06,$46,$46,$3c,$3c,$00,$00				;' 5'
+ChNum6:				DB		$1c,$1c,$20,$20,$60,$60,$7c,$7c,$66,$66,$66,$66,$3c,$3c,$00,$00				;' 6'
+ChNum7:				DB		$7e,$7e,$06,$06,$0e,$0e,$1c,$1c,$18,$18,$18,$18,$18,$18,$00,$00				;' 7'
+ChNum8:				DB		$3c,$3c,$66,$66,$66,$66,$3c,$3c,$66,$66,$66,$66,$3c,$3c,$00,$00				;' 8'
+ChNum9:				DB		$3c,$3c,$66,$66,$66,$66,$3e,$3e,$06,$06,$0c,$0c,$38,$38,$00,$00				;' 9'
+ChLetA:				DB		$3c,$3c,$66,$66,$66,$66,$7e,$7e,$66,$66,$66,$66,$66,$66,$00,$00				;' A'
+ChLetB:				DB		$7c,$7c,$66,$66,$66,$66,$7c,$7c,$66,$66,$66,$66,$7c,$7c,$00,$00				;' B'
+ChLetC:				DB		$3c,$3c,$62,$62,$60,$60,$60,$60,$60,$60,$62,$62,$3c,$3c,$00,$00				;' C'
+ChLetD:				DB		$7c,$7c,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$7c,$7c,$00,$00				;' D'
+ChLetE:				DB		$7e,$7e,$60,$60,$60,$60,$7c,$7c,$60,$60,$60,$60,$7e,$7e,$00,$00				;' E'
+ChLetF:				DB		$7e,$7e,$60,$60,$60,$60,$7c,$7c,$60,$60,$60,$60,$60,$60,$00,$00				;' F'
+ChLetG:				DB		$3c,$3c,$62,$62,$60,$60,$6e,$6e,$66,$66,$66,$66,$3e,$3e,$00,$00				;' G'
+ChLetH:				DB		$66,$66,$66,$66,$66,$66,$7e,$7e,$66,$66,$66,$66,$66,$66,$00,$00				;' H'
+ChLetI:				DB		$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$00,$00				;' I'
+ChLetJ:				DB		$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$46,$46,$3c,$3c,$00,$00				;' J'
+ChLetK:				DB		$66,$66,$6c,$6c,$78,$78,$70,$70,$78,$78,$6c,$6c,$66,$66,$00,$00				;' K'
+ChLetL:				DB		$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$7c,$7c,$00,$00				;' L'
+ChLetM:				DB		$fc,$fc,$d6,$d6,$d6,$d6,$d6,$d6,$d6,$d6,$c6,$c6,$c6,$c6,$00,$00				;' M'
+ChLetN:				DB		$62,$62,$72,$72,$7a,$7a,$5e,$5e,$4e,$4e,$46,$46,$42,$42,$00,$00				;' N'
+ChLetO:				DB		$3c,$3c,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$3c,$3c,$00,$00				;' O'
+ChLetP:				DB		$7c,$7c,$66,$66,$66,$66,$7c,$7c,$60,$60,$60,$60,$60,$60,$00,$00				;' P'
+ChLetQ:				DB		$3c,$3c,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$3c,$3c,$06,$06				;' Q'
+ChLetR:				DB		$7c,$7c,$66,$66,$66,$66,$7c,$7c,$66,$66,$66,$66,$66,$66,$00,$00				;' R'
+ChLetS:				DB		$3c,$3c,$62,$62,$70,$70,$3c,$3c,$0e,$0e,$46,$46,$3c,$3c,$00,$00				;' S'
+ChLetT:				DB		$7e,$7e,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$00,$00				;' T'
+ChLetU:				DB		$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$3c,$3c,$00,$00				;' U'
+ChLetV:				DB		$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$64,$64,$78,$78,$00,$00				;' V'
+ChLetW:				DB		$c6,$c6,$c6,$c6,$c6,$c6,$d6,$d6,$d6,$d6,$d6,$d6,$fc,$fc,$00,$00				;' W'
+ChLetX:				DB		$66,$66,$66,$66,$66,$66,$3c,$3c,$66,$66,$66,$66,$66,$66,$00,$00				;' X'
+ChLetY:				DB		$66,$66,$66,$66,$66,$66,$3c,$3c,$18,$18,$18,$18,$18,$18,$00,$00				;' Y'
+ChLetZ:				DB		$7e,$7e,$0e,$0e,$1c,$1c,$38,$38,$70,$70,$60,$60,$7e,$7e,$00,$00				;' Z'
+					IF		!DEF(__GLOBALDATA_I__)
+__GLOBALDATA_I__	SET		1
+
+					GLOBAL	g_stack
+					GLOBAL	g_stackTop
+					GLOBAL	g_vblFrameCount
+					GLOBAL	g_cpuType
+					GLOBAL	g_vblDone
+;					GLOBAL	g_receivePacket
+;					GLOBAL	g_sendPacket
+					GLOBAL	g_isServer
+					GLOBAL	g_packetNumber
+					GLOBAL	g_packetIndex
+					GLOBAL	g_connectState
+;					GLOBAL	g_rxBuffer
+;					GLOBAL	g_txBuffer
+					GLOBAL	g_isSIOComplete
+					GLOBAL	g_isSIOError
+					GLOBAL	LinkPalette
+
+k_CONNECT_TIMEOUT	EQU		60*30									; wait 30 seconds for connection to timeout
+							RSRESET
+k_CONNECTION_NONE			RB	1									; connection is not yet established
+k_CONNECTION_ESTABLISHED	RB	1									; connection with remote gameboy is established
+k_CONNECTION_NO_REMOTE		RB	1									; there is no remote gameboy
+k_CONNECTION_LOST			RB	1									; connection with remote gameboy has been lost
+
+k_PACKET_ID_START	EQU		$01										; starting packet #
+k_PACKET_ID_END		EQU		$7F										; ending packet #
+
+k_PACKET_ADDRESS	EQU		$81										; start address where packet is stored/retrieved in hiram
+
+; don't mess around with these codes
+; if you do alter their values, DO NOT!!! use either $00 or $FF
+k_SERVER_CODE		EQU		$01										; "I.M. Server" transmit code
+k_CLIENT_CODE		EQU		$FE										; "I.R. Client" transmit code
+k_PACKET_LENGTH		EQU		2										; length of transmission packet, must be less than 15 per video frame
+
+				; local variables
+g_localVars0		EQU		k_HIRAM
+g_localVars1		EQU		k_HIRAM+16
+g_localVars2		EQU		k_HIRAM+32
+g_localVars3		EQU		k_HIRAM+48
+g_localVars4		EQU		k_HIRAM+64
+
+					ENDC
+					INCLUDE	"Standard.i"
+					INCLUDE	"GlobalData.i"
+					INCLUDE	"Initialise.i"
+
+
+					SECTION "Local Vars",HRAM[k_HIRAM]
+localVars0:			DS		16																										;[BEN REMOVE]
+localVars1:			DS		16																										;[BEN REMOVE]
+localVars2:			DS		16																										;[BEN REMOVE]
+localVars3:			DS		16																										;[BEN REMOVE]
+
+					SECTION	"GlobalData",BSS[$C000]					; must absolutely, positively, be here
+g_cpuType:			DS		1										; gameboy console type id										[BEN REMOVE]
+g_stack:			DS		254										; reserve 255 bytes for stack (must be on a 255 byte boundary)	[BEN REMOVE]
+g_stackTop:															; top of stack													[BEN REMOVE]
+					DT_VARS
+g_vblFrameCount:	DS		2										; VBL frame counter												[BEN REMOVE]
+g_vblDone:			DS		1										; vbl flag (true=vbl is complete)								[BEN REMOVE]
+
+					DT_VARS
+; these two buffers contain the next packet to send, and the last packet received
+;g_receivePacket:	DS		k_PACKET_LENGTH							; data that has been received
+;g_sendPacket:		DS		k_PACKET_LENGTH							; data that is ready to transmit
+; these two buffers should never be accessed by the game program
+; these are the "live" transmit/receive buffers
+g_connectState:		DS		1										; serial connection state, $00 = no connection established, $01 = connection, $02 = no remote gameboy, $03 = connection lost
+g_isServer:			DS		1										; $01 = SERVER, $02 = CLIENT
+g_packetNumber:		DS		1										; packet number for sync detection
+g_packetIndex:		DS		1										; current rx/tx index in to packet data
+g_isSIOComplete:	DS		1										; is serial I/O complete?
+g_isSIOError:		DS		1										; was there a serial I/O error?
+;					SECTION	"ReceiveBuffer",BSS[$C100]				; must absolutely, positively, be on a 256 byte boundary
+;g_rxBuffer:			DS		k_PACKET_LENGTH+1						; data that is being received
+;					SECTION	"TransmitBuffer",BSS[$C200]				; must absolutely, positively, be on a 256 byte boundary
+;g_txBuffer:			DS		k_PACKET_LENGTH+1						; data that is being transmitted
+
+
+					DT_DATA
+; temporary palette for displaying debug messages
+LinkPalette:		DW		(2<<10)|(2<<5)|(2),(5<<10)|(5<<5)|(5),(10<<10)|(10<<5)|(10),$7FFF										;[BEN REMOVE]
+;********************************************************************
+;																	*
+; NAME:	HARDWARE.I													*
+; AUTH: JLloyd -- 99/04/12											*
+; NOTES: Based on JeffF's hardware defines.							*
+;																	*
+;																	*
+;********************************************************************
+
+
+; add these registers when you have time
+;TIMA_REG	(*(UBYTE *)0xFF05)	/* Timer counter */
+;TMA_REG		(*(UBYTE *)0xFF06)	/* Timer modulo */
+;TAC_REG		(*(UBYTE *)0xFF07)	/* Timer control */
+;RP_REG		(*(UBYTE *)0xFF56)	/* IR port */
+
+
+r_MBC5_ROM_SEL		EQU		$2000									; rom bank select (write here with bank # (0-63 on GBC with 8Mbit cart))
+r_MBC5_ROM_SEL_MSB	EQU		$3000
+
+r_MBC5_WRAM_SEL		EQU		$4000									; ram bank select (write here with bank # (0-7 on GBC))
+
+k_GB_REGS			EQU		$FF00
+
+; VRAM
+; GameBoy Video RAM extends from $8000 to $A000, a total of 8KB
+k_VRAM				EQU		$8000
+k_VRAM_LENGTH		EQU		$2000
+k_VRAM_START		EQU		k_VRAM
+k_VRAM_END			EQU		((k_VRAM+k_VRAM_LENGTH)-1)
+
+k_VRAM_BG_LOW		EQU		$9800
+k_VRAM_BG_HIGH		EQU		$9C00
+k_VRAM_TILE_BANK_0	EQU		$8000
+k_VRAM_TILE_BANK_1	EQU		$8800
+k_VRAM_TILE_BANK_2	EQU		$9000
+
+; HIRAM
+; Gameboy HIRAM extends from $FF80 to $FFFF, a total of 128 bytes
+k_HIRAM				EQU		$FF80
+k_HIRAM_LENGTH		EQU		$7F
+k_HIRAM_START		EQU		k_HIRAM
+k_HIRAM_END			EQU		((k_HIRAM+k_HIRAM_LENGTH)-1)
+
+; WRAM
+; GameBoy Work RAM extends from $C000 to $E000, a total of 8KB on
+; GB and 32KB bank-switched on GBC with 8KB visible at any one time.
+k_RAM				EQU		$C000									; $C000->$E000
+k_RAM_LENGTH		EQU		$2000
+k_RAM_START			EQU		k_RAM
+k_RAM_END			EQU		((k_RAM+k_RAM_LENGTH)-1)
+
+k_RAM_BANK_UPR		EQU		$D000
+k_RAM_BANK_LENGTH	EQU		$1000
+k_RAM_BANK_UPR_START	EQU	k_RAM_BANK_UPR
+k_RAM_BANK_UPR_END	EQU		((k_RAM_BANK_UPR+k_RAM_BANK_LENGTH)-1)
+
+
+; OAM
+; GameBoy Object Attribute Map RAM extends from $FE00 to $FE9F. A
+; total of 160 bytes.
+k_OAMRAM			EQU		$FE00
+k_OAMRAM_LENGTH		EQU		$A0
+k_OAMRAM_START		EQU		k_OAMRAM
+k_OAMRAM_END		EQU		((k_OAMRAM+k_OAMRAM_LENGTH)-1)
+
+_AUD3WAVERAM		EQU		$FF30									; $FF30->$FF3F		; not sure!
+
+
+k_COLOUR_GREY			EQU		3
+k_COLOUR_DARK_GREY		EQU		2
+k_COLOUR_LIGHT_GREY		EQU		1
+k_COLOUR_TRANSPARENT	EQU		0
+
+
+
+; --
+; -- OAM flags
+; --
+
+; OAM
+; GameBoy Object Attribute Map describes the attributes for sprites
+; bit positions in the Object Attribute Map
+k_OAM_BIT_PRIORITY	EQU		7										; object priority
+k_OAM_BIT_VFLIP		EQU		6										; object vertical flip
+k_OAM_BIT_HFLIP		EQU		5										; object horizontal flip
+k_OAM_BIT_PAL_BANK	EQU		4										; palette bank
+k_OAM_BIT_TILE_BANK	EQU		3										; tile bank
+k_OAM_BIT_PAL0		EQU		2										; palette bit 0
+k_OAM_BIT_PAL1		EQU		1										; palette bit 1
+k_OAM_BIT_PAL2		EQU		0										; palette bit 2
+
+; mask values in the Object Attribute Map
+k_OAMM_PRIORITY	EQU		%10000000								; object priority
+k_OAMM_VFLIP	EQU		%01000000								; object vertical flip
+k_OAMM_HFLIP	EQU		%00100000								; object horizontal flip
+k_OAMM_PAL_BANK_LO	EQU		%11101111							; palette bank #0 (OBJ0PAL)
+k_OAMM_PAL_BANK_HI	EQU		%00010000							; palette bank #1 (OBJ1PAL)
+k_OAMM_TILE_BANK_LO	EQU		%11110111								; tile bank #0
+k_OAMM_TILE_BANK_HI	EQU		%00001000								; tile bank #1
+k_OAMM_PAL		EQU		%00000111								; palette mask
+k_OAMM_PAL0		EQU		%00000000								; palette 0
+k_OAMM_PAL1		EQU		%00000100								; palette 1
+k_OAMM_PAL2		EQU		%00000010								; palette 2
+k_OAMM_PAL3		EQU		%00000110								; palette 3
+k_OAMM_PAL4		EQU		%00000001								; palette 4
+k_OAMM_PAL5		EQU		%00000101								; palette 5
+k_OAMM_PAL6		EQU		%00000011								; palette 6
+k_OAMM_PAL7		EQU		%00000111								; palette 7
+
+
+;********************************************************************
+; NAME: P1 -- Joypad Input											*
+; INFO: $FF00, R/W													*
+;																	*
+; This register is used for reading the joypad buttons. Only		*
+; certain bits of the register can be written to.					*
+;																	*
+;********************************************************************
+r_P1				EQU		$FF00
+
+k_P1F_5				EQU		%00100000								; P5 out port (write)
+k_P1F_4				EQU		%00010000								; P4 out port (write)
+k_P1F_3				EQU		%00001000								; P3 out port (read)
+k_P1F_2				EQU		%00000100								; P2 out port (read)
+k_P1F_1				EQU		%00000010								; P1 out port (read)
+k_P1F_0				EQU		%00000001								; P0 out port (read)
+
+
+;********************************************************************
+; NAME: SB -- Serial IO Data Buffer									*
+; INFO: $FF01, R/W													*
+;																	*
+; This register handles data for the gameboy serial port. It		*
+; handles both incoming and outgoing data. To determine the			*
+; direction and status, the Serial IO Control Register (SC) should	*
+; be consulted.														*
+;																	*
+;********************************************************************
+r_SB				EQU		$FF01
+
+k_SIO_CLOCK			EQU		$01
+k_SIO_TRANSMIT		EQU		$80
+
+;********************************************************************
+; NAME: SC -- Serial IO Control										*
+; INFO: $FF02, R/W													*
+;																	*
+;********************************************************************
+r_SC				EQU		$FF02
+
+
+;********************************************************************
+; NAME: DIV -- Timer Divider Register								*
+; INFO: $FF04, R/W													*
+;																	*
+;********************************************************************
+k_DIV				EQU		$FF04
+
+
+;********************************************************************
+; NAME: LCDC -- LCD Control											*
+; INFO: $FF40, R/W													*
+;																	*
+;********************************************************************
+r_LCDC				EQU		$FF40
+
+k_LCDCM_LCD_ON		EQU		%10000000								; lcd display on
+k_LCDCM_LCD_OFF		EQU		((~k_LCDCM_LCD_ON)&$00FF)			; lcd display off
+k_LCDCM_WIN9C00		EQU		%01000000								; window screen display data select $9C00
+k_LCDCM_WIN9800		EQU		((~k_LCDCM_WIN9C00)&$00FF)			; window screen display data select $9800
+k_LCDCM_WIN_ON		EQU		%00100000								; window display on
+k_LCDCM_WIN_OFF		EQU		((~k_LCDCM_WIN_ON)&$00FF)			; window display off
+k_LCDCM_BG8000		EQU		%00010000								; background character data select $8000
+k_LCDCM_BG8800		EQU		((~k_LCDCM_BG8000)&$00FF)			; background character data select $8800
+k_LCDCM_BG9C00		EQU		%00001000								; background screen display data select $9C00
+k_LCDCM_BG9800		EQU		((~k_LCDCM_BG9C00)&$00FF)			; background screen display data select $9800
+k_LCDCM_OBJ16		EQU		%00000100								; object size 16 pixels
+k_LCDCM_OBJ8		EQU		((~k_LCDCM_OBJ16)&$00FF)			; object size 8 pixels
+k_LCDCM_OBJ_ON		EQU		%00000010								; obj display
+k_LCDCM_OBJ_OFF		EQU		((~k_LCDCM_OBJ_ON)&$00FF)			; obj display
+k_LCDCM_BG_ON		EQU		%00000001								; background display on
+k_LCDCM_BG_OFF		EQU		((~k_LCDCM_BG_ON)&$00FF)			; background display off
+																	
+k_LCDCB_LCD_VIS		EQU		7										; lcd visible
+k_LCDCB_WIN_DS		EQU		6										; window display data select
+k_LCDCB_WIN_VIS		EQU		5										; window visible
+k_LCDCB_BGD_DS		EQU		4										; background character data select
+k_LCDCB_BGS_DS		EQU		3										; background screen data select
+k_LCDCB_OBJ_SIZE	EQU		2										; object size (8 or 16 pixels high)
+k_LCDCB_OBJ_VIS		EQU		1										; object visible
+k_LCDCB_BG_VIS		EQU		0										; background visible
+
+
+;********************************************************************
+; NAME: STAT -- LCD Status											*
+; INFO: $FF41, R/W													*
+;																	*
+;********************************************************************
+r_STAT				EQU		$FF41
+
+k_STATF_LYC			EQU		%01000000								; LYCEQULY coincidence (selectable)
+k_STATF_MODE10		EQU		%00100000								; mode 10
+k_STATF_MODE01		EQU		%00010000								; mode 01 (V-Blank)
+k_STATF_MODE00		EQU		%00001000								; mode 00 (H-Blank)
+k_STATF_LYCF		EQU		%00000100								; coincidence Flag
+k_STATF_HB			EQU		%00000000								; H-Blank
+k_STATF_VB			EQU		%00000001								; V-Blank
+k_STATM_OAM			EQU		%00000010								; OAM-RAM is in use by system
+k_STATM_VRAM		EQU		%00000001								; vram is in use by system
+k_STATM_LCD			EQU		%00000011								; both OAM and VRAM used by system
+
+
+;********************************************************************
+; NAME: SCY -- Scroll Screen Y										*
+; INFO: $FF42, R/W													*
+;																	*
+;********************************************************************
+r_SCY				EQU		$FF42
+
+
+;********************************************************************
+; NAME: SCX -- Scroll Screen X										*
+; INFO: $FF43, R/W													*
+;																	*
+;********************************************************************
+r_SCX					EQU		$FF43
+
+
+;********************************************************************
+; NAME: LY -- LCDC Y Coordinate										*
+; INFO: $FF44, R													*
+;																	*
+; This register is the current scan line value. It increments as	*
+; each horizontal line of the screen is drawn. Valid values are		*
+; between 0 to 153. Values 144 to 153 are the vertical blanking		*
+; period.															*
+;																	*
+;********************************************************************
+r_LY				EQU		$FF44
+
+
+
+;********************************************************************
+; NAME: LYC -- LY compare											*
+; INFO: $FF45, R/W													*
+;																	*
+; This register is used to trigger the LCDC interrupt when the		*
+; scanline currently being drawn is equal to this register. When	*
+; equal the STATF_LYC flag is set in STAT.							*
+;																	*
+;********************************************************************
+r_LYC					EQU		$FF45
+
+
+; --
+; -- DMA ($FF46)
+; -- DMA Transfer and Start Address (W)
+; --
+r_DMA					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
+; --
+r_BGP					EQU		$FF47
+
+
+; --
+; -- OBP0 ($FF48)
+; -- Object Palette 0 Data (W)
+; --
+; -- See BGP for info
+; --
+r_OBP0					EQU		$FF48
+
+
+; --
+; -- OBP1 ($FF49)
+; -- Object Palette 1 Data (W)
+; --
+; -- See BGP for info
+; --
+r_OBP1					EQU		$FF49
+
+;
+; -- VRAM BANK ($FF4F)
+; -- VRAM bank select (W)
+r_VRAM_BANK				EQU		$FF4F
+k_VRAM_BANK_LOWER		EQU		$0
+k_VRAM_BANK_UPPER		EQU		$1
+						
+						
+r_BCPS					EQU		$FF68								; BG color palette specification
+r_BCPD					EQU		$FF69								; BG color palette data
+r_OCPS					EQU		$FF6A								; OBJ color palette specification
+r_OCPD					EQU		$FF6B								; OBJ color palette data
+r_SVBK					EQU		$FF70								; WRAM bank
+
+
+; --
+; -- HDMA1 ($FF51)
+; -- Horizontal Blanking, General Purpose DMA (W)
+; --
+r_HDMA1					EQU		$FF51
+
+
+; --
+; -- HDMA2 ($FF52)
+; -- Horizontal Blanking, General Purpose DMA (W)
+; --
+r_HDMA2				EQU		$FF52
+
+
+; --
+; -- HDMA3 ($FF53)
+; -- Horizontal Blanking, General Purpose DMA (W)
+; --
+r_HDMA3				EQU		$FF53
+
+
+; --
+; -- HDMA4 ($FF54)
+; -- Horizontal Blanking, General Purpose DMA (W)
+; --
+r_HDMA4				EQU		$FF54
+
+
+; --
+; -- HDMA5 ($FF55)
+; -- Horizontal Blanking, General Purpose DMA (R/W)
+; --
+r_HDMA5				EQU		$FF55
+
+
+; --
+; -- RP ($FF56)
+; -- Infrared Communications Port (R/W)
+; --
+r_RP				EQU		$FF56
+
+
+
+
+
+; --
+; -- IF ($FF0F)
+; -- Interrupt Flag (R/W)
+; --
+; -- IE ($FFFF)
+; -- Interrupt Enable (R/W)
+; --
+r_IF	EQU $FF0F
+r_IE	EQU $FFFF
+
+k_IEF_HILO			EQU		%00010000								; Transition from High to Low of Pin number P10-P13
+k_IEF_SERIAL		EQU		%00001000								; Serial I/O transfer end
+k_IEF_TIMER			EQU		%00000100								; Timer Overflow
+k_IEF_LCDC			EQU		%00000010								; LCDC (see STAT)
+k_IEF_VBLANK		EQU		%00000001								; V-Blank
+
+
+; --
+; -- WY ($FF4A)
+; -- Window Y Position (R/W)
+; --
+; -- 0 <EQU WY <EQU 143
+; --
+r_WY				EQU		$FF4A
+
+
+; --
+; -- WX ($FF4B)
+; -- Window X Position (R/W)
+; --
+; -- 7 <EQU WX <EQU 166
+; --
+r_WX				EQU		$FF4B
+
+; --
+; -- KEY1 ($FF4D)
+; -- CPU Speed (R/W)
+; --
+r_KEY1				EQU		$FF4D										; cpu speed control register
+
+
+
+
+;***************************************************************************
+;*
+;* 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/NR42 ($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)
+; --
+rNR42_2	EQU $FF22
+rAUD4POLY	EQU rNR42_2
+
+
+; --
+; -- AUD4GO/NR43 ($FF23)
+; -- (has wrong name and value (ff30) in Dr.Pan's doc!)
+; --
+; -- Bit 7 -   Inital
+; -- Bit 6 -   Counter/consecutive selection
+; --
+rNR43	EQU $FF23
+rAUD4GO	EQU rNR43	; silly name!
+
+
+k_GB_VRAM_W_PIX		EQU		256										; width of vram in pixels
+k_GB_VRAM_H_PIX		EQU		256										; height of vram in pixel
+k_GB_VRAM_W_BYTE	EQU		32										; width of vram in bytes
+k_GB_VRAM_H_BYTE	EQU		32										; height of vram in bytes
+
+k_GB_SCR_W_PIX		EQU		160										; width of visible screen in pixels
+k_GB_SCR_H_PIX		EQU		144										; height of visible screen in pixels
+k_GB_SCR_W_BYTE		EQU		20										; width of visible screen in bytes
+k_GB_SCR_H_BYTE		EQU		18										; height of visible screen in bytes
+k_GB_SCR_CTR_X		EQU		(k_GB_SCR_W_PIX/2)						; horizontal center of gameboy screen in pixels
+k_GB_SCR_CTR_Y		EQU		(k_GB_SCR_H_PIX/2)						; vertical center of gameboy screen in pixels
+					IF		!DEF(__INITIALISE_I__)
+__INITIALISE_I__	SET		1
+					GLOBAL	Initialise
+					GLOBAL	InitStaticSprites
+					GLOBAL	InitStaticIcons
+					GLOBAL	InitGame
+					GLOBAL	InitLevel
+					GLOBAL	InitSprites
+					GLOBAL	InitPalettes
+					ENDC
+					INCLUDE "Standard.i"
+					INCLUDE	"GlobalData.i"
+					INCLUDE "Utility.i"
+					INCLUDE "Initialise.i"
+					INCLUDE "Font.i"
+					INCLUDE "Interrupts.i"
+
+
+;************************************************************************
+;																		*
+; NAME:	InitMemory														*
+;																		*
+;************************************************************************
+					FT_GAME
+InitMemory:			
+					PUSHALL											; save registers
+				; clear bank 0 of wram from stack top to end of ram bank
+					LD		HL,g_stackTop							; -> start of work ram
+					LD		BC,k_RAM_BANK_LENGTH-(g_stackTop-k_RAM)	; clear 4kb of ram
+					CALL	MemoryZeroBig							; clear work ram
+				; clear oam ram
+					LD		HL,k_OAMRAM								; -> oam ram
+					LD		B,$A0									; clear 160 bytes of oam ram
+					CALL	MemoryZeroSmall							; clear oam ram
+				; clear hi ram
+					LD		HL,k_HIRAM								; -> hi-ram
+					LD		B,k_HIRAM_LENGTH						; clear 70 bytes of hi-ram (but not the stack area)
+					CALL	MemoryZeroSmall							; clear hi-ram
+				; clear all wram that can be bank switched
+					LD		A,7										; set ram bank counter to last available ram bank
+.ClearWorkRAM:		LDH		[r_SVBK],A								; switch ram bank
+					LD		HL,k_RAM_BANK_UPR						; -> start of upper ram bank
+					LD		BC,k_RAM_BANK_LENGTH					; set length of memory to length of one ram bank
+					PUSH	AF										; save register
+					CALL	MemoryZeroBig							; clear 4KB of ram
+					POP		AF										; restore register
+					DEC		A										; decrement ram bank counter
+					JR		NZ,.ClearWorkRAM						; no, another ram bank
+					LD		A,1										; 
+					LDH		[r_SVBK],A								; restore ram bank that was here before entering function
+					POPALL											; restore registers
+					RET												; exit function
+
+
+;************************************************************************
+;																		*
+; NAME:	InitDisplay														*
+;																		*
+;************************************************************************
+					FT_GAME
+InitDisplay:		CALL	LCD_Off									; turn display off
+					XOR		A										; load #0
+					LDH		[r_SCX],A								; clear background scroll X register
+					LDH		[r_SCY],A								; clear background scroll Y register
+					LDH		[r_STAT],A								; clear lcd status register
+					LDH		[r_WY],A								; clear window y position
+					LDH		[r_WX],A								; set window x position
+					LDH		A,[r_LCDC]								; pick up current lcd configuration
+					AND		A,k_LCDCM_BG8000						; set base tile set to use
+					LDH		[r_LCDC],A								; store new lcd configuration
+				; initialise a palette
+					LD		HL,LinkPalette							; -> link up palette data
+					LD		B,0										; load palette #0
+					LD		C,1										; load 1 palette
+					CALL	SetBGP									; set background palette
+					RET												; exit function
+
+
+;************************************************************************
+;																		*
+; NAME:	InitBackground													*
+;																		*
+;************************************************************************
+					FT_GAME
+InitBackground:
+					SHOW_BG											; turn on background
+					RET												; exit function
+
+
+;************************************************************************
+;																		*
+; NAME:	Initialise														*
+;																		*
+; This is the general purpose initialisation function that is called	*
+; when the Gameboy is first switched on.								*
+;																		*
+;************************************************************************
+					FT_GAME
+Initialise:			DI												; disable interrupts
+					LD		D,A										; copy gameboy type
+					XOR		A										; set interrupt flag to no interrupts
+					LDH		[r_IE],A								; clear all interrupts
+					LD		[r_IF],A								; clear all pending interrupts flags
+					CALL	LCD_Off									; turn off the lcd
+					CALL	InitMemory								; initialise memory
+					LD		A,D										; retrieve gameboy type
+					LD		[g_cpuType],A							; store gameboy type
+					CALL	InitFont								; initialise font
+					CALL	InitDisplay								; initialise display
+					CALL	InitInterrupts							; initialise game interrupt routines
+					CALL	LCD_On									; turn on lcd display
+					XOR		A										; clear interrupt flag
+					LD		[r_IF],A								; clear all pending interrupts flags
+					EI												; enable interrupts
+					NOP												; safety nop after an EI
+					RET												; exit function
+
+					IF		!DEF(__INTERRUPTS_I__)
+__INTERRUPTS_I__	SET		1
+
+					GLOBAL	g_lcdIntrCode
+					GLOBAL	g_vblIntrCode
+					GLOBAL	InitInterrupts
+					GLOBAL	InitGameInter
+					GLOBAL	InitMenuInter
+
+k_MAX_INTR_SIZE		EQU		128
+
+COPY_INTR:			MACRO
+					IF \2>k_MAX_INTR_SIZE
+						FAIL	"Interrupt function is too large"
+					ENDC
+					LD		HL,\1
+					LD		DE,\2
+					LD		BC,\3
+					CALL	MemCopyBig
+					ENDM
+
+					ENDC
+					INCLUDE	"Standard.i"
+					INCLUDE	"GlobalData.i"
+					INCLUDE "Interrupts.i"
+
+					SECTION	"Interrupt Code",BSS
+g_vblIntrCode:		DS		k_MAX_INTR_SIZE
+g_sioIntrCode:		DS		k_MAX_INTR_SIZE
+
+					SECTION	"GameboyROM",HOME[$0]
+					DS		$40
+
+					SECTION	"VBL Interrupt",HOME[$40]
+					JP		g_vblIntrCode							; execute vbl interrupt
+
+					SECTION	"LCD Interrupt",HOME[$48]
+					RETI											; exit interrupt
+
+					SECTION	"Timer Interrupt",HOME[$50]
+					RETI											; exit interrupt
+
+					SECTION	"Serial Interrupt",HOME[$58]
+					JP		g_sioIntrCode							; execute serial I/O interrupt
+
+					SECTION	"Joypad Interrupt",HOME[$60]
+					RETI											; exit interrupt
+
+
+;********************************************************************
+; NAME:	DefaultVBLInter												*
+; DEST: None														*
+;																	*
+;																	*
+;********************************************************************
+					FT_INTR
+DefaultVBLInter:	PUSHALL											; preserve registers
+					LD		A,[g_vblFrameCount]						; pick up current frame count								(4)
+					AND		$01										; mask vbl frame counter for odd/even frames				(2)
+					JR		Z,.EveryFrame							; is this an even frame? yes, so don't scan the joypad		(3/2)
+					CALL	ScanJoypad								; update joypad status										(6)
+.EveryFrame:		LD		A,[g_vblFrameCount]						; pick up current frame count								(4)
+					INC		A										; increment frame #											(1)
+					LD		[g_vblFrameCount],A						; store new frame count value								(4)
+					LD		A,[g_vblFrameCount+1]					; pick up current frame count								(4)
+					ADC		0										; increment frame #											(1)
+					LD		[g_vblFrameCount+1],A					; store new frame count value								(4)
+					LD		A,$01									; indicate that vbl is complete								(2)
+					LD		[g_vblDone],A							; set vbl done flag											(4)
+					POPALL											; restore registers
+					RETI											; exit interrupt
+DefaultVBLInterEnd:
+
+
+;********************************************************************
+; NAME:	DefaultSIOInter												*
+; DEST: None														*
+;																	*
+;																	*
+;********************************************************************
+					FT_INTR
+DefaultSIOInter:	RETI											; exit interrupt
+DefaultSIOInterEnd:
+
+
+;********************************************************************
+; NAME:	MenuSIOInter												*
+; DEST: None														*
+;																	*
+; This function handles a serial I/O interrupt generated during the	*
+; menu processing part of a game. It 
+;																	*
+;********************************************************************
+					FT_INTR
+MenuSIOInter:		PUSH	AF										; preserve register
+					LDH		A,[r_SB]								; get received byte
+					CP		k_CLIENT_CODE							; client code received?
+					JR		NE,.NotClient							; no, so this machine is not a server
+					LD		A,k_CONNECTION_ESTABLISHED				; indicate that connection is established
+					LD		[g_connectState],A						; set connection code
+					LD		A,k_TRUE								; set flag value
+					LD		[g_isServer],A							; set is server flag to indicate this machine is server
+					POP		AF										; restore register
+					RETI											; exit interrupt
+.NotClient:			CP		k_SERVER_CODE							; server code received?
+					JR		NE,.NotServer							; no, so this machine is not a client
+					LD		A,k_CONNECTION_ESTABLISHED				; indicate that connection is established
+					LD		[g_connectState],A						; set connection code
+					XOR		A										; clear flag value
+					LD		[g_isServer],A							; clear is server flag to indicate this machine is client
+					POP		AF										; restore register
+					RETI											; exit interrupt
+					DW		$4E4F									; pad bytes
+.NotServer:			CP		$FF										; no remote gameboy code?
+					JR		EQ,.NoRemote							; yes, so handle an empty connection
+					CP		$00										; no remote gameboy code?
+					JR		EQ,.NoRemote							; yes, so handle an empty connection
+					LD		A,k_CLIENT_CODE							; set code to send to remote machine
+					LDH		[r_SB],A								; place code to transmit in serial buffer
+					LD		A,k_SIO_TRANSMIT						; set "ready to transmit" on serial port with external clock
+					LDH		[r_SC],A								; enable transmission on serial port
+					POP		AF										; restore register
+					RETI											; exit function
+.NoRemote:			LD		A,k_CONNECTION_NO_REMOTE				; indicate that no remote gameboy was found
+					LD		[g_connectState],A						; set connection code
+					POP		AF										; restore register
+					RETI											; exit interrupt
+MenuSIOInterEnd:
+
+
+;********************************************************************
+; NAME:	GameSIOInter												*
+; DEST: None														*
+;																	*
+;																	*
+;********************************************************************
+					FT_INTR
+GameSIOInter:		PUSH	BC										; preserve register
+					PUSH	AF										; preserve register
+				; get received data
+					LDH		A,[r_SB]								; pick up data from serial port
+					LD		B,A										; save it for later
+				; packet # has been transmitted?
+					LD		A,[g_packetIndex]						; pick up packet index
+					CP		k_PACKET_LENGTH							; all data & frame transmitted?
+					JR		EQ,.EndOfPacket							; yes, process end of packet
+				; last data byte transmitted?
+					CP		k_PACKET_LENGTH-1						; all data transmitted?
+					JR		LT,.MoreData							; no, send more data
+				; all data transmitted - transmit packet #
+					INC		A										; increment packet index
+					LD		[g_packetIndex],A						; store new packet index
+					ADD		k_PACKET_ADDRESS-1						; add base address of packet data
+					LD		C,A										; set index to store received data at
+					LD		A,B										; get received data
+					LD		[C],A									; store received data
+					LD		A,[g_packetNumber]						; pick up packet #
+					LDH		[r_SB],A								; put packet # on serial port
+					LD		A,[g_isServer]							; pick up "i am server" flag
+					OR		k_SIO_TRANSMIT							; bitwise-or with "begin transmission" flag
+					LDH		[r_SC],A								; start serial data transmission
+					POP		AF										; restore register
+					POP		BC										; restore register
+					RETI											; exit interrupt
+					DW		$4F54,$414B,$5500						; pad bytes
+				; handle end of packet transmission
+.EndOfPacket:		LD		A,[g_packetNumber]						; pick up current packet #
+					CP		B										; compare with received packet #
+					JR		EQ,.SIOComplete							; packet numbers match? yes, so serial I/O completed ok
+					LD		A,B										; get received packet #
+					CP		$00										; compare with open connection code
+					JR		EQ,.ConnectionLost						; connection lost? yes, so handle connection error
+					CP		$FF										; compare with open connection code
+					JR		EQ,.ConnectionLost						; connection lost? yes, so handle connection error
+				; indicate an sio error
+					LD		A,k_TRUE								; set flag to true
+					LD		[g_isSIOError],A						; indicate there was a serial i/o error
+					JR		.SIOComplete							; complete serial i/o
+				; indicate connection has been lost
+.ConnectionLost:	LD		A,k_CONNECTION_LOST						; set connection state to "connection lost"
+					LD		[g_connectState],A						; store new connection state
+				; indicate that sio is complete
+.SIOComplete:		LD		A,k_TRUE								; set flag to true
+					LD		[g_isSIOComplete],A						; indicate that serial i/o is complete
+					POP		AF										; restore register
+					POP		BC										; restore register
+					RETI											; exit interrupt
+				; store received data
+.MoreData:			ADD		k_PACKET_ADDRESS						; add base address of where packet data is stored
+					LD		C,A										; set index to store received data at
+					LD		A,B										; get received data
+					LD		[C],A									; store received data
+				; transmit new data
+					INC		C										; -> next data to transmit
+					LD		A,[C]									; pick up data to transmit
+					LDH		[r_SB],A								; place data on serial port
+					LD		A,[g_isServer]							; pick up "i am server" flag
+					OR		k_SIO_TRANSMIT							; bitwise-or with "begin transmission" flag
+					LDH		[r_SC],A								; start serial data transmission
+					LD		A,C										; get index of current packet data
+					SUB		k_PACKET_ADDRESS						; subtract base address of where packet data is stored
+					LD		[g_packetIndex],A						; store new packet index
+.Exit:				POP		AF										; restore register
+					POP		BC										; restore register
+					RETI											; exit interrupt
+GameSIOInterEnd:
+
+
+;********************************************************************
+; NAME:	InitInterrupts												*
+;																	*
+; This function initialises the default interrupts, it copies any	*
+; required interrupt routines in to RAM at their desginated			*
+; addresses. It disables interrupts by default but does not, and	*
+; should never be made to, enable them. This function is designed	*
+; to be called as part of the gameboy initialisation routine and	*
+; interrupts should only be enabled after all other general setup	*
+; is complete.														*
+;																	*
+;********************************************************************
+					FT_GAME
+InitInterrupts:		PUSHALL											; preserve registers
+					DI												; disable interrupts
+				; copy interrupt code to ram
+					COPY_INTR	DefaultVBLInter, DefaultVBLInterEnd-DefaultVBLInter, g_vblIntrCode
+				; enable interrupts
+					XOR		A										; clear interrupts
+					LDH		[r_IF],A								; clear all pending interrupts flags
+					LD		A,k_IEF_VBLANK							; set vblank interrupts on
+					LDH		[r_IE],A								; set interrupt enable flags
+					EI												; re-enable interrupts
+					NOP												; pause for 1 cycle
+					POPALL											; restore registers
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	InitGameInter												*
+;																	*
+; This function initialises the in-game interrupts, it copies any	*
+; required interrupt routines in to RAM at their desginated			*
+; addresses.														*
+;																	*
+;********************************************************************
+					FT_GAME
+InitGameInter:		PUSHALL											; preserve registers
+					DI												; disable interrupts
+				; copy interrupt code to ram
+					COPY_INTR	DefaultVBLInter, DefaultVBLInterEnd-DefaultVBLInter, g_vblIntrCode
+					COPY_INTR	GameSIOInter, GameSIOInterEnd-GameSIOInter, g_sioIntrCode
+				; enable interrupts
+					XOR		A										; clear interrupts
+					LDH		[r_IF],A								; clear all pending interrupts flags
+					LD		A,(k_IEF_VBLANK | k_IEF_SERIAL)			; set vblank interrupts on
+					LDH		[r_IE],A								; set interrupt enable flags
+					EI												; re-enable interrupts
+					NOP												; pause for 1 cycle
+					POPALL											; restore registers
+					RET												; exit function
+
+
+;********************************************************************
+; NAME:	InitMenuInter												*
+;																	*
+; This function initialises the menu interrupts, it copies any		*
+; required interrupt routines in to RAM at their desginated			*
+; addresses.														*
+;																	*
+;********************************************************************
+					FT_GAME
+InitMenuInter:		PUSHALL											; preserve registers
+					DI												; disable interrupts
+				; copy interrupt code to ram
+					COPY_INTR	DefaultVBLInter, DefaultVBLInterEnd-DefaultVBLInter, g_vblIntrCode
+					COPY_INTR	MenuSIOInter, MenuSIOInterEnd-MenuSIOInter, g_sioIntrCode
+				; enable interrupts
+					XOR		A										; clear interrupts
+					LDH		[r_IF],A								; clear all pending interrupts flags
+					LD		A,(k_IEF_VBLANK | k_IEF_SERIAL)			; set vblank & sio interrupts on
+					LDH		[r_IE],A								; set interrupt enable flags
+					EI												; re-enable interrupts
+					NOP												; pause for 1 cycle
+					POPALL											; restore registers
+					RET												; exit function
+
+
+					IF		!DEF(__JOYPAD_I__)
+__JOYPAD_I__		SET		1
+
+					GLOBAL	ScanJoypad
+					GLOBAL	g_joypadStatus
+					GLOBAL	g_joypadChange
+
+k_JOYPAD_START		EQU		$80
+k_JOYPAD_SELECT		EQU		$40
+k_JOYPAD_B			EQU		$20
+k_JOYPAD_A			EQU		$10
+k_JOYPAD_DOWN		EQU		$08
+k_JOYPAD_UP			EQU		$04
+k_JOYPAD_LEFT		EQU		$02
+k_JOYPAD_RIGHT		EQU		$01
+
+;
+; Read current status of joypad
+ReadJoypad:			MACRO
+					LD		A,[g_joypadStatus]
+					ENDM
+
+;
+; Read joypad status and determine which keys have been pressed since last read
+ReadJoypadChange:	MACRO
+					LD		A,[g_joypadChange]
+					ENDM
+
+					ENDC
+					INCLUDE	"Standard.i"
+					INCLUDE "Joypad.i"
+
+					DT_VARS	"Joypad"
+g_joypadStatus:		DS		1										; current joypad status
+g_joypadChange:		DS		1										; changes since previous joypad scan
+
+;********************************************************************
+;																	*
+; NAME: ScanJoypad													*
+; REGS: A,B															*
+;																	*
+; This function scans the joypad and stores the current status and	*
+; the changes that have occured since the previous scan.			*
+;																	*
+;********************************************************************
+					FT_GAME
+				; prepare hardware for first read
+ScanJoypad:			LD		A,k_P1F_5								; set value to output on line P15 ($20)
+					LDH		[r_P1],A								; output to joypad control lines ($FF00)
+					LDH		A,[r_P1]								; read & discard first value returned ($FF00)
+				; get first 4 bits of joypad status
+					LDH		A,[r_P1]								; read status lines ($FF00)
+					CPL												; joypad input from h/w is inverted, so flip it
+					AND		A,$0F									; grab START, SELECT, B, & A buttons
+					SWAP	A										; move to high nibble
+					LD		B,A										; save button status for later use
+				; prepare hardware for second read
+					LD		A,k_P1F_4								; set value to output on line P15 ($10)
+					LDH		[r_P1],A								; output to joypad control lines ($FF00)
+					LDH		A,[r_P1]								; read & discard first few values returned ($FF00)
+					LDH		A,[r_P1]								; ($FF00)
+					LDH		A,[r_P1]								; ($FF00)
+					LDH		A,[r_P1]								; ($FF00)
+					LDH		A,[r_P1]								; ($FF00)
+				; get next 4 bits of joypad status
+					LDH		A,[r_P1]								; read status lines ($FF00)
+					CPL												; flip inverted input from h/w
+					AND		$0F										; grab d-pad buttons
+					OR		B										; mask all joypad buttons together
+					SWAP	A										; swap both joypad nibbles
+				; calculate joypad changes
+					LD		B,A										; copy current joypad input status
+					LD		A,[g_joypadStatus]						; pick up previous joypad input status
+					XOR		A,B										; determine which buttons changed since last read
+					AND		A,B										; determine those buttons that have been pressed since last read
+					LD		[g_joypadChange],A						; save joypad change information
+				; store current joypad status
+					LD		A,B										; retrieve current joypad input status
+					LD		[g_joypadStatus],A						; save new joypad input status
+					LD		A,k_P1F_5|k_P1F_4						; set value to reset P14/P15 lines ($30)
+					LDH		[r_P1],A								; reset joypad h/w ($FF00)
+					RET												; exit function
+
+
+					INCLUDE	"Banks.i"
+					INCLUDE	"Font.i"
+
+					DT_GFX_DATA
+Font:
+					DB		$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;'  '
+					DB		$3c,$3c,$66,$66,$6e,$6e,$76,$76,$66,$66,$66,$66,$3c,$3c,$00,$00 ;' 0'
+					DB		$18,$18,$38,$38,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$00,$00 ;' 1'
+					DB		$3c,$3c,$66,$66,$0e,$0e,$1c,$1c,$38,$38,$70,$70,$7e,$7e,$00,$00 ;' 2'
+					DB		$7e,$7e,$0c,$0c,$18,$18,$3c,$3c,$06,$06,$46,$46,$3c,$3c,$00,$00 ;' 3'
+					DB		$0c,$0c,$1c,$1c,$2c,$2c,$4c,$4c,$7e,$7e,$0c,$0c,$0c,$0c,$00,$00 ;' 4'
+					DB		$7e,$7e,$60,$60,$7c,$7c,$06,$06,$06,$06,$46,$46,$3c,$3c,$00,$00 ;' 5'
+					DB		$1c,$1c,$20,$20,$60,$60,$7c,$7c,$66,$66,$66,$66,$3c,$3c,$00,$00 ;' 6'
+					DB		$7e,$7e,$06,$06,$0e,$0e,$1c,$1c,$18,$18,$18,$18,$18,$18,$00,$00 ;' 7'
+							
+					DB		$3c,$3c,$66,$66,$66,$66,$3c,$3c,$66,$66,$66,$66,$3c,$3c,$00,$00 ;' 8'
+					DB		$3c,$3c,$66,$66,$66,$66,$3e,$3e,$06,$06,$0c,$0c,$38,$38,$00,$00 ;' 9'
+					DB		$3c,$3c,$66,$66,$66,$66,$7e,$7e,$66,$66,$66,$66,$66,$66,$00,$00 ;' A'
+					DB		$7c,$7c,$66,$66,$66,$66,$7c,$7c,$66,$66,$66,$66,$7c,$7c,$00,$00 ;' B'
+					DB		$3c,$3c,$62,$62,$60,$60,$60,$60,$60,$60,$62,$62,$3c,$3c,$00,$00 ;' C'
+					DB		$7c,$7c,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$7c,$7c,$00,$00 ;' D'
+					DB		$7e,$7e,$60,$60,$60,$60,$7c,$7c,$60,$60,$60,$60,$7e,$7e,$00,$00 ;' E'
+					DB		$7e,$7e,$60,$60,$60,$60,$7c,$7c,$60,$60,$60,$60,$60,$60,$00,$00 ;' F'
+					DB		$3c,$3c,$62,$62,$60,$60,$6e,$6e,$66,$66,$66,$66,$3e,$3e,$00,$00 ;' G'
+							
+					DB		$66,$66,$66,$66,$66,$66,$7e,$7e,$66,$66,$66,$66,$66,$66,$00,$00 ;' H'
+					DB		$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$00,$00 ;' I'
+					DB		$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$46,$46,$3c,$3c,$00,$00 ;' J'
+					DB		$66,$66,$6c,$6c,$78,$78,$70,$70,$78,$78,$6c,$6c,$66,$66,$00,$00 ;' K'
+					DB		$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$7c,$7c,$00,$00 ;' L'
+					DB		$fc,$fc,$d6,$d6,$d6,$d6,$d6,$d6,$d6,$d6,$c6,$c6,$c6,$c6,$00,$00 ;' M'
+					DB		$62,$62,$72,$72,$7a,$7a,$5e,$5e,$4e,$4e,$46,$46,$42,$42,$00,$00 ;' N'
+					DB		$3c,$3c,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$3c,$3c,$00,$00 ;' O'
+							
+					DB		$7c,$7c,$66,$66,$66,$66,$7c,$7c,$60,$60,$60,$60,$60,$60,$00,$00 ;' P'
+					DB		$3c,$3c,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$3c,$3c,$06,$06 ;' Q'
+					DB		$7c,$7c,$66,$66,$66,$66,$7c,$7c,$66,$66,$66,$66,$66,$66,$00,$00 ;' R'
+					DB		$3c,$3c,$62,$62,$70,$70,$3c,$3c,$0e,$0e,$46,$46,$3c,$3c,$00,$00 ;' S'
+					DB		$7e,$7e,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$00,$00 ;' T'
+					DB		$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$3c,$3c,$00,$00 ;' U'
+					DB		$66,$66,$66,$66,$66,$66,$66,$66,$66,$66,$64,$64,$78,$78,$00,$00 ;' V'
+					DB		$c6,$c6,$c6,$c6,$c6,$c6,$d6,$d6,$d6,$d6,$d6,$d6,$fc,$fc,$00,$00 ;' W'
+							
+					DB		$66,$66,$66,$66,$66,$66,$3c,$3c,$66,$66,$66,$66,$66,$66,$00,$00 ;' X'
+					DB		$66,$66,$66,$66,$66,$66,$3c,$3c,$18,$18,$18,$18,$18,$18,$00,$00 ;' Y'
+					DB		$7e,$7e,$0e,$0e,$1c,$1c,$38,$38,$70,$70,$60,$60,$7e,$7e,$00,$00 ;' Z'
+[objects]
+LinkUp.obj
+ROMHeader.obj
+Utility.obj
+Initialise.obj
+Joypad.obj
+GlobalData.obj
+CopyData.obj
+Interrupts.obj
+Font.obj
+FontData.obj
+banks.obj
+
+#[libraries]
+#c:\gameboy\lib\mos.lib
+
+[output]
+LinkUp.gb
+# Microsoft Developer Studio Project File - Name="LinkUp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) External Target" 0x0106
+
+CFG=LinkUp - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "LinkUp.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "LinkUp.mak" CFG="LinkUp - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "LinkUp - Win32 Release" (based on "Win32 (x86) External Target")
+!MESSAGE "LinkUp - Win32 Debug" (based on "Win32 (x86) External Target")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""$/LinkUp/Asm", DGDAAAAA"
+# PROP Scc_LocalPath "."
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Cmd_Line "NMAKE /f LinkUp.mak"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "LinkUp.exe"
+# PROP BASE Bsc_Name "LinkUp.bsc"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Cmd_Line "nmake /f "LinkUp.mak""
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "LinkUp.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Cmd_Line "NMAKE /f LinkUp.mak"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "LinkUp.exe"
+# PROP BASE Bsc_Name "LinkUp.bsc"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Cmd_Line "c:\gameboy\bin\make -a -c -f "makefile.mk""
+# PROP Rebuild_Opt "-B"
+# PROP Target_File "LinkUp.gb"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ENDIF 
+
+# Begin Target
+
+# Name "LinkUp - Win32 Release"
+# Name "LinkUp - Win32 Debug"
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+!ENDIF 
+
+# Begin Group "Libraries"
+
+# PROP Default_Filter "*.s;*.i"
+# Begin Source File
+
+SOURCE=.\CopyData.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\CopyData.s
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+# PROP Ignore_Default_Tool 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\hardware.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Joypad.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Joypad.s
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\ROMHeader.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\ROMHeader.S
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Shift.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Utility.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Utility.s
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# End Group
+# Begin Group "LinkUp"
+
+# PROP Default_Filter "*.s;*.i"
+# Begin Source File
+
+SOURCE=.\Banks.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Banks.s
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Default_Tool 1
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+# PROP Ignore_Default_Tool 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\conditional.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Conditional.s
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+# PROP Ignore_Default_Tool 1
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Font.i
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Font.s
+
+!IF  "$(CFG)" == "LinkUp - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "LinkUp - Win32 Debug"
+
+# PROP Intermediate_Dir "Output"