;==========================================================================================
;
;   UNOFFICIAL SNES POWERPAK FIRMWARE V2.01 (CODENAME: "SIMBA")
;   (c) 2012/2013 by ManuLöwe (http://www.manuloewe.de/)
;
;	*** PRINT HANDLER ***
;	Code in this file based on v1.0X code written by:
;	- bunnyboy (SNES PowerPak creator), (c) 2009
;	- Neviksti (subroutines ??), (c) 2002
;
;==========================================================================================



; ************************ Main print function *************************

; This alternately writes doubled values of ASCII characters to the
; BG2/BG1 text buffer while keeping track of which BG to use next via
; the BGPrintMon variable (start = $00 = BG2, $01 = BG1).

; The ASCII values need to be doubled because both fonts have empty 8x8
; tiles before or after each character. By not advancing the text cursor
; position when using BG2, all of this makes it possible to work around
; Mode 5's 16x8 tile size limitation, with the main drawback that the
; text engine uses up both available BG layers.

; In: A -- ASCII code to print
; Out: none
; Modifies: P



Print_BGX:					; expectations: A/Mem=8bit, X/Y=16bit
	pha
	lda BGPrintMon
	bne +					; if BG monitor value is not zero, use BG1

	inc BGPrintMon				; otherwise, change value and use BG2

	pla
	phx

	ldx Cursor
	asl					; character code * 2 so it matches hi-res font tile location
	sta TxtBuf2bpp, X			; write it to the BG2 text buffer

	bra __PrintBGXDone			; ... and done

+	stz BGPrintMon				; reset BG monitor value

	pla
	phx

	ldx Cursor
	asl					; character code * 2
	sta TxtBuf4bpp, X			; write it to the BG1 text buffer
	inx					; ... and advance text cursor position
	stx Cursor

__PrintBGXDone:

	plx
rts



; ********************* String processing function *********************

;PrintF -- Print a Formatted, NULL terminated string to Stdout
;In:   X -- points to format string
;      Y -- points to parameter buffer
;Out: none
;Modifies: none
;Notes:
;     Supported Format characters:
;       %s -- sub-string (reads 16-bit pointer from Y data)
;       %d -- 16-bit Integer (reads 16-bit data from Y data)
;       %b -- 8-bit Integer (reads 8-bit data from Y data)
;       %x -- 8-bit hex Integer (reads 8-bit data from Y data)
;       %% -- normal %
;       \n -- Newline
;       \t -- Tab
;       \b -- Page break	>> REMOVED2.0
;       \\ -- normal slash
;     String pointers all refer to current Data Bank (DB)

PrintF:
	ldx strPtr2

PrintFStart:
	PHP
	PHA
	PHX
	PHY

	rep #XY_8BIT				; A/mem=8bit, X/Y=16bit
	sep #A_8BIT

PrintFLoop:
	LDA $0000,X				; read next format string character
	BEQ PrintFDone				; check for NULL terminator
	INX					; increment input pointer
	CMP #'%'
	BEQ PrintFFormat			; handle format character
	CMP #'\'
	BEQ PrintFControl			; handle control character

NormalPrint:
	JSR Print_BGX				; print the character on BGX (via buffer)
	BRA PrintFLoop

PrintFDone:
	PLY
	PLX
	PLA
	PLP
RTS



PrintFControl:
	LDA $0000,X				; read control character
	BEQ PrintFDone				; check for NULL terminator
	INX					; increment input pointer
	CMP #'n'
_cn:	BNE _ct
	rep #$30				; 16b mem, 16b X
	LDA Cursor				; get current position
	CLC
	ADC #$0020				; move to the next line
	AND #$FFE0
	ora #minPrintX				; add horizontal indention
	STA Cursor				; save new position
	sep #A_8BIT				; 8b mem, 16b X
	stz BGPrintMon				; reset BG monitor value
	BRA PrintFLoop
_ct:	CMP #'t'
;	BNE _cb
	BNE _defaultC
	rep #$30				; 16b mem, 16b X
	LDA Cursor				; get current position
	CLC
;	ADC #$0008				; move to the next tab
;	AND #$FFF8
	adc #$0004				; smaller tab size (4 tiles = 8 hi-res characters)
	and #$fffc
;	adc #$0002				; use this instead for even smaller tabs
;	and #$fffe
	STA Cursor				; save new position
	sep #A_8BIT				; 8b mem, 16b X
	stz BGPrintMon				; reset BG monitor value
	BRA PrintFLoop
;_cb:	CMP #'b'				; page break, fixed (& removed since there's no practical use for it)
;	BNE _defaultC
;	pha
;	phx
;	jump jPrintClearScreen
;	ldx #32*minPrintY+minPrintX
;	stx Cursor
;	plx
;	pla
;	stz BGPrintMon				; reset BG monitor value
;	BRA PrintFLoop
_defaultC:
	LDA #'\'				; normal backslash
	BRA NormalPrint

PrintFFormat:
	LDA $0000,X				; read format character
	BEQ PrintFDone				; check for NULL terminator
	INX					; increment input pointer
_sf:	CMP #'s'
	BNE _df
	PHX					; preserve current format string pointer
	LDX 0,Y					; load sub-string pointer
	INY
	INY
	JSR PrintFStart				; call PrintF recursively with sub-string
	PLX
	BRA PrintFLoop
_df:	CMP #'d'
	BNE _bf
	JSR PrintInt16				; print 16-bit integer
	bra PrintFLoop
_bf:	CMP #'b'
	BNE _xf
	JSR PrintInt8				; print 8-bit integer
	bra PrintFLoop
_xf:	CMP #'x'
	BNE _defaultF
	JSR PrintHex8				; print 8-bit hex integer
	bra PrintFLoop
_defaultF:
	LDA #'%'
	bra NormalPrint



; ******************** Number processing functions *********************

;PrintInt16 -- Read a 16-bit value pointed to by Y and print it to stdout
;In:  Y -- Points to integer in current data bank
;Out: Y=Y+2
;Modifies: P
;Notes: Uses Print to output ASCII to stdout

PrintInt16:					; assumes 8b mem, 16b index
	LDA #$00
	PHA					; push $00
	LDA $0000,Y
	STA $4204				; DIVC.l
	LDA $0001,Y
	STA $4205				; DIVC.h  ... DIVC = [Y]
	INY
	INY

DivLoop:
	LDA #$0A	
	STA $4206				; DIVB = 10 --- division starts here (need to wait 16 cycles)
	NOP					; 2 cycles
	NOP					; 2 cycles
	NOP					; 2 cycles
	PHA					; 3 cycles
	PLA					; 4 cycles
	LDA #'0'				; 2 cycles
	CLC					; 2 cycles
	ADC $4216				; A = '0' + DIVC % DIVB
	PHA					; push character
	LDA $4214				; Result.l -> DIVC.l
	STA $4204
	BEQ _Low_0
	LDA $4215				; Result.h -> DIVC.h
	STA $4205
	BRA DivLoop

_Low_0:
	LDA $4215				; Result.h -> DIVC.h
	STA $4205
	BEQ IntPrintLoop			; if ((Result.l==$00) and (Result.h==$00)) then we're done, so print
	BRA DivLoop

IntPrintLoop:					; until we get to the end of the string...
	PLA					; keep pulling characters and printing them
	BEQ _EndOfInt
	JSR Print_BGX				; write them to the text buffer
	BRA IntPrintLoop

_EndOfInt:

RTS



;PrintInt8 -- Read an 8-bit value pointed to by Y and print it to stdout
;In:  Y -- Points to integer in current data bank
;Out: Y=Y+1
;Modifies: P
;Notes: Uses Print to output ASCII to stdout

PrintInt8:					; assumes 8b mem, 16b index
	LDA $0000,Y
	INY

PrintInt8_noload:
	STA $4204
	LDA #$00
	STA $4205
	PHA
	BRA DivLoop

PrintInt16_noload:				; assumes 8b mem, 16b index
	LDA #$00
	PHA					; push $00
	STX $4204				; DIVC = X
	JSR DivLoop



;PrintHex8 -- Read an 8-bit value pointed to by Y and print it in hex to stdout
;In:  Y -- Points to integer in current data bank
;Out: Y=Y+1
;Modifies: P
;Notes: Uses Print to output ASCII to stdout

PrintHex8:					; assumes 8b mem, 16b index
	lda $0000,Y
	iny

PrintHex8_noload:
	pha
	lsr A
	lsr A
	lsr A
	lsr A
	jsr PrintHexNibble
	pla
	and #$0F
	jsr PrintHexNibble
rts	

PrintHexNibble:					; assumes 8b mem, 16b index
	cmp #$0A
	bcs _nletter
	clc
	adc #'0'
	jsr Print_BGX				; write it to the text buffer
rts

_nletter: 	
	clc
	adc #'A'-10		
	jsr Print_BGX				; write it to the text buffer
rts



; ************************* Clearing functions *************************

PrintClearLine:
	pha					; A = number of line to clear
	asl a
	asl a
	asl a
	asl a
	asl a
	sta Cursor
	pla
	lsr a
	lsr a
	lsr a
	sta Cursor+1

	ldx Cursor
	ldy #$0000
	lda #$40				; = asl #$20 (space's ASCII code)

-	sta TxtBuf2bpp, x			; clear BG2 text buffer
	sta TxtBuf4bpp, x			; clear BG1 text buffer
	inx
	iny
	cpy #$0020				; $20 chars = one "line"
	bne -
rts



PrintClearScreen:
	ldx #$0000
	lda #$40				; = asl #$20 (space's ASCII code)

-	sta TxtBuf2bpp, x			; purge BG2 text buffer
	sta TxtBuf4bpp, x			; purge BG1 text buffer, too
	inx
	cpx #$0400				; 1024 bytes
	bne -
rts

; **********************************************************************
