Sunday, August 26, 2018

64 column text on a 256x192 graphics screen -> 6502 Part 1

The 6502 version of the 64 column text code but it also supports 80 columns.
It can be assembled for the Acorn Atom (64 columns), Atari (64 or 80 columns), Plus/4 (80 columns), and C64 (80 columns)
80 columns requires 320 x 192, or 320 x 200 graphics resolutions.

While this code has much in common with the 6803 version, there are some significant differences.
Notes:
  1. The scroll uses columns rather than just rows.  This was needed for speed.
  2. The address calculation and font data tables are unique to the 6502.
  3. This is a version from earlier this month but it is not the current version I'm working on.
  4. The Plus/4 code is almost complete, and the C64 code is preliminary.  Neather have been assembled or tested yet, and the screen address tables might still need updating.  
  5. I had trouble getting the assembler to properly generate the Atari display lists aligned on 256 byte boundaries, so you'll probably see some code that needs manual intervention reserving bytes to force the alignment.  This is likely due to needing a new config setup for the assembler.
  6. The Atom code should still work, but I haven't assembled or tested it since adding the changes for the Atari or Commodores.
  7. Blogger barfed on the 1600+ lines of assembly, so the code has been split in two.


;**************************************************
;* File: print64.6502
;**************************************************
;* Copyright (c) 2015, 2016, 2018 James Diffendaffer
;**************************************************
;* Description:
;*  Emulates an 64 or 80 character by 24 line text display using 
;*  4 bit wide characters on a 256 or 320 * 192 graphics display depending
;*  on the target hardware.
;*  This supports the Acorn Atom, Atari 8 bit, Commodore Plus/4, and Commodore 64
;*
;*  Contains functions to print a string at the current screen location,
;*  print strings @ a specific screen location, line wrapping, scrolling,
;*  clear screen, the character generator and a font.
;*  Characters are stored with identical data in the left and right nibble
;*  to make rendering faster and several loops have been unrolled for speed.
;*  This code has been tested but has at least one known bug.
;*  Assembles with the AS65 assembler included with the CC65 C compiler package.
;*  
;*  Derived from my Acorn Atom code
;**************************************************
;* Version history
;*  Version  Date               Description
;*     0.19   Aug   6, 2018      Completed (mostly) initial Plus/4 version and added C64 hardware changes
;*     0.18   Aug  31, 2016      Added code to disable non maskable interrupts from the Atari hardware.  MVN works now.
;*     0.17   Aug  27, 2016      80 Column code is working, added 65802/65816 memory move instruction option for scroll
;*     0.16   Aug  26, 2016      Changed page zero use for Atari, now runs fine in 64 columns.
;*     0.15   Aug  21, 2016      Added initial Atari 8 bit graphics support
;*     0.14   Nov   4, 2015      Added initial support for 80 columns and Commodore Plus/4, just starting Atari demo code
;*     0.13   Oct   6, 2015      Initial version with ability to print 2 characters at a time
;*     0.12   Oct   3, 2015      Additional unrolling of scroll loop, more code cleanup
;*     0.11   Oct   1, 2015      Integrated clearing last line of text display into the scroll
;*                                 Code cleanup, inverted screen and BGColor addition
;*     0.09   Sept 30, 2015      Changed text printing code to use EOR to save clock cycles and shorten the code.
;*                                 Added scroll that uses unrolled column scroll for faster speed, some dead code cleanup
;*     0.08   Sept 30, 2015      Added a CLC to the string generator code and changed CLC to SEC in print64 - Thanks Dave!
;*     0.07   Sept 30, 2015      Added CLC in several places to fix printing, scrolling, etc.  Initial release version.
;*     0.06   Sept 29, 2015      Converted to AS65 assembler format, fixed a lot of # and > related bugs
;*     0.05   Sept 28, 2015      Bringing code in line with Z80 & 6803 versions
;*	   0.04   Sept 20, 2015      Replaced LDA TAY with LDY and reordered code in left and right nibble print routines
;*     0.03   Sept 19, 2015      Added Atom ATM file header and started Plus/4 80 column version.
;*     0.02   Sept  9, 2015      Finished print@ and print functions
;*	   0.01   Sept  8, 2015      Created initial 6502 character generation code
;**************************************************

;*********************************************
;* Pick the target machine here by setting to 1
;*********************************************
.define AcornAtom	0
.define Plus4		1
.define C64			0
.define Atari		0
;*********************************************
;* Set to 1 to use 65816 code
;*********************************************
.define Use65816	0

;*********************************************
;* Font and and other universal defines
;*********************************************
.define FontHeight		8				; number of rows high the font is on screen
.define efont			EOF-font		; end of font
.define	unrollmore 1					; increase loop unrolling



;*********************************************
;* 65816 support
;*********************************************
.if Use65816 = 1
.P816
;Memory Move Negative.  Move from hi to lo address.
;Memory is moved at the rate of seven clock cycles per byte.
; MVN increments the X and Y registers, and decrements A
.macro	MOVEMEMN	SourceAddress,DestAddress,BytesToMove,SourceBank,DestBank
	SEI
	
;	LDA	#0
;	STA	NMIEN					; turn off ATARI non maskable interrupts for 65816
;								; if you want to have it restored, you'll need a copy of the setting somewhere
	clc
	xce							; native mode
	rep	#$31					; set A, X, and Y to 16 bit, clear carry
.A16							; Tell assembler Accumulator is 16 bit
.I16							; Tell assembler Index registers are 16 bit
	LDX	#SourceAddress			; The source address for the memory move
	LDY	#DestAddress				; The destination address for the memory move
	LDA	#BytesToMove-1			; The number of bytes we want to move + 1 because MVN needs it
	MVN	SourceBank,DestBank		; RAM banks, should be 00,00 on 64K system
	sep	#$31					; set A, X, and Y to 8 bits, set carry
;	sec
	xce							; emulated mode
.A8								; Tell assembler Accumulator is 8 bit
.I8								; Tell assembler Index registers are 8 bit
;	LDA	NMIENSHADOWREGISTER
;	STA	NMIEN					; restore non maskable interrupts for 65816
	CLI
.endmacro
.endif


;*********************************************
;* Acorn Atom specific defines
;*********************************************
.if AcornAtom = 1
ScreenAdr:		equ		$8000			; screen address of Atom
.define BytesPerLine			32				; screen width of RG6 mode
ScreenHeight:	equ		192				; screen height of RG6 mode
.endif


;*********************************************
;* Commodore Plus/4 specific defines
;*********************************************
.if Plus4 = 1
//Commodore Plus/4 related settings
TED			EQU 	$FF00				; TED Base Address
TEDVMR		EQU		TED+6				; TED Video Mode register
VBASEREG	EQU		TED+20				; 5 bit video matrix base register
ColorRAM	EQU		$8000				; Base address of color RAM
VIDBASE		EQU		$8C00				; Base address of our Screen memory
VASet		EQU		$88					; Video Address setting for VBASEREG
VMSet		EQU		#$36				;  %00110110
										; from bit 7 down to bit 0:
										;  0 - test bit, always 0
										;  0 - Extended Color Mode off
										;  1 - Bitmap Mode On
										;  1 - Screen On
										;  0 - 24 Rows
										; 110 - Vertical Scroll Position

ScreenAdr:		equ		VIDBASE			; screen address of Plus/4
.define BytesPerLine	40				; screen width of 2 color bitmapped mode
ScreenHeight:	equ		200				; screen height
.endif


;*********************************************
;* Commodore 64 specific defines
;*********************************************
.if C64 = 1
ScreenAdr:		equ		$6000			; screen address of Plus/4
.define BytesPerLine	40				; screen width of 2 color bitmapped mode
ScreenHeight:	equ		200				; screen height
.endif


;*********************************************
; Atari specific defines
;*********************************************
.if Atari = 1
.define BytesPerLine			32				; screen width of mode 8 narrow playfield
;.define BytesPerLine			40				; screen width of mode 8 normal playfield

;This all means my DLIST needs 3 blank lines, mode 8 + LSM, screen address, 89 mode 8s, mode 8 + LSM, next screen address, 101 mode 8s, JVB dlist
.if BytesPerLine = 32
.define SCREEN 			30720 ;($9000-(32*64)-4096)				;6144 bytes , 2 4K blocks needed,  128 rows in last 4K block, 64 in first 4K block
.elseif BytesPerLine = 40
.define SCREEN	29168	; ($9000-(40*90)-4096)				;7680 bytes , 2 4K blocks needed,  102 rows in last 4K block, 90 in first 4K block
.endif	
.define	ScreenAdr		SCREEN ;$74C0 ;36864-2880-4096			; screen address of Atari
.define ScreenHeight	192				; screen height of mode 8
.endif

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

	.BSS	

.ZEROPAGE				; page zero variables
;	.org	$0010		; Acorn Atom
	.org	$0040		; page zero variables
		
string:		.res	2		; string pointer
prntat:		.res	2		; Print @ location like Microsoft BASIC
row:		.res	1		;
col:		.res	1		;
temp0:		.res	2		; temporary storage
fscreen:	.res	2		; screen pointer for character generator
fscreen1:	.res	2		; screen pointer for character generator
firstchar:	.res	1
secondchar:	.res	1
length:		.res	2		; for 16 bit operations
ytemp:		.res	1		; temporary storage for y
BGColor:	.res	1		; screen background color

.CODE


;****************************
; Acorn Atom build
;****************************
.if AcornAtom = 1
	.org	$2B00 - 22		; start 22 bytes early for header
;****************************
;* Acorn Atom ATM file header
;****************************
FNAME:		.byt	"PRINT64",0,0,0,0,0,0,0,0,0		;File Name up to 12 characters + zero padding
ADDRESS:	.word	START			;current address is load address
EXECADD:	.word	START			;current address is execute address
FLENGTH:	.word	(EOF-START)		;file length = end of file value (EOF) munus start address
;****************************
;		org	$2B00			; free RAM on Atom
.endif


;****************************
; Commodore Plus/4 build
;****************************
.if Plus4 = 1
	.org	$4000-2			; start address -2 for prg header
	.word	START			; the start address
	
	;DB $0B,$10,0,0,$9E,"4109",0,0,0
.endif



;****************************
; Atari build
;****************************
.if Atari = 1
;.segment  "BSS"
;	.org	$0000


; xex block header
;.segment "EXEHDR"
	.org	$0600 - 7
    .word $FFFF
    .word START				; code/data start
    .word EOF - 1;START		; end

	.org	$0600
.endif





	.code
START:

		
;**************************************************
;* graphics text routine macros
;**************************************************

; To be used similar to Microsoft BASIC's PRINT@
.macro	PRINTAT	loc,str
	lda #<loc
	sta prntat
	lda #>loc
	sta prntat+1
	lda #>str
	sta string
	lda #>str
	sta string+1
	jsr print_at
.endmacro

; print a string starting at the current position
.macro PRINT	str
	lda #<str
	sta string
	lda #>str
	sta string+1
	jsr print
.endmacro


; incrament a 16 bit number
.macro  inc16   addr
.scope
	inc	addr
	bne	Skip
	inc	addr+1
Skip:
.endscope
.endmacro

; decrement a 16 bit number
.macro  dec16   addr
.scope
	dec	addr
	bne	Skip
	dec	addr+1
Skip:
.endscope
.endmacro

; invert the font data to you can print in inverse text
; `
.macro InvertFont	mfont,msize
	lda	#<mfont
	sta	fscreen
	lda	#>mfont
	sta	fscreen+1
	lda	#<msize
	sta	length
	lda	#>msize
	sta	length+1
	jsr	invert_mem
.endmacro



;**************************************************
;* NAME: textdemo
;**************************************************
;* DESCRIPTION:
;*  a short program to demonstrate the use of 
;*  routines in the graphics library
;**************************************************
Textdemo:
	;save registers
	pha
	txa
	pha
	tya
	pha

.if Use65816 = 1
.if Atari = 1
	LDA	#0
	STA	NMIEN					; turn off ATARI non maskable display interrupts for 65816
								; if you keep a copy of NMIEN somewhere, the macro can be altered to disable/enable the interrupts
.endif	
.endif
	
	jsr	InitScreen		; call unique setup routine for the machine this is assembled for
	
	
	
	
	;	InvertFont(font,efont)
;	lda	#<font
;	sta	fscreen
;	lda	#>font
;	sta	fscreen+1
;	;1344 bytes
;	lda	#$40
;	sta	length
;	lda	#$06	; should be 06 by my code in the invert_mem doesn't work correctly yet
;	sta	length+1
;	jsr	invert_mem

	
	lda		#0
	sta		row
	sta		col
	
; 64/80 character/line demo, prints entire character set
	lda		#<String
	sta		string
	lda		#>String
	sta		string+1
	ldy		#0
	
	lda		#' '				; the first character in the font
@loop:
	sta		(string),y
	iny
	clc
	adc		#1					; increment a
	cmp		#'~'+1				; are we past the last character in the font?
	bne		@loop
	lda		#0
	sta		(string),y
Endless:
	PRINT	String				; print the string we just built
	clc
	bcc	  Endless
	
	;restore registers
	pla
	tay
	pla
	tax
	pla

	rts
	
;**************************************************
;* cls
;**************************************************
;* clears the Atom hi-res screen
;**************************************************

cls:
.if BytesPerLine = 32
	lda		#0
	tax
	lda		BGColor
@sloop:
	sta		ScreenAdr+0*FontHeight*BytesPerLine,x
	sta		ScreenAdr+1*FontHeight*BytesPerLine,x
	sta		ScreenAdr+2*FontHeight*BytesPerLine,x
	sta		ScreenAdr+3*FontHeight*BytesPerLine,x
	sta		ScreenAdr+4*FontHeight*BytesPerLine,x
	sta		ScreenAdr+5*FontHeight*BytesPerLine,x
	sta		ScreenAdr+6*FontHeight*BytesPerLine,x
	sta		ScreenAdr+7*FontHeight*BytesPerLine,x
	sta		ScreenAdr+8*FontHeight*BytesPerLine,x
	sta		ScreenAdr+9*FontHeight*BytesPerLine,x
	sta		ScreenAdr+10*FontHeight*BytesPerLine,x
	sta		ScreenAdr+11*FontHeight*BytesPerLine,x
	sta		ScreenAdr+12*FontHeight*BytesPerLine,x
	sta		ScreenAdr+13*FontHeight*BytesPerLine,x
	sta		ScreenAdr+14*FontHeight*BytesPerLine,x
	sta		ScreenAdr+15*FontHeight*BytesPerLine,x
	sta		ScreenAdr+16*FontHeight*BytesPerLine,x
	sta		ScreenAdr+17*FontHeight*BytesPerLine,x
	sta		ScreenAdr+18*FontHeight*BytesPerLine,x
	sta		ScreenAdr+19*FontHeight*BytesPerLine,x
	sta		ScreenAdr+20*FontHeight*BytesPerLine,x
	sta		ScreenAdr+21*FontHeight*BytesPerLine,x
	sta		ScreenAdr+22*FontHeight*BytesPerLine,x
	sta		ScreenAdr+23*FontHeight*BytesPerLine,x		; last line of 192 line display
.if ScreenHeight = 200
	sta		ScreenAdr+24*FontHeight*BytesPerLine,x		; for 200 line high display
.endif
	inx
	beq		@nxt
	jmp		@sloop
@nxt:
.endif

.if BytesPerLine = 40
	lda		#0
	tax
	lda		BGColor
@sloop:
	sta		ScreenAdr+0*FontHeight*BytesPerLine,x
	sta		ScreenAdr+0*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+1*FontHeight*BytesPerLine,x
	sta		ScreenAdr+1*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+2*FontHeight*BytesPerLine,x
	sta		ScreenAdr+2*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+3*FontHeight*BytesPerLine,x
	sta		ScreenAdr+3*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+4*FontHeight*BytesPerLine,x
	sta		ScreenAdr+4*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+5*FontHeight*BytesPerLine,x
	sta		ScreenAdr+5*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+6*FontHeight*BytesPerLine,x
	sta		ScreenAdr+6*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+7*FontHeight*BytesPerLine,x
	sta		ScreenAdr+7*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+8*FontHeight*BytesPerLine,x
	sta		ScreenAdr+8*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+9*FontHeight*BytesPerLine,x
	sta		ScreenAdr+9*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+10*FontHeight*BytesPerLine,x
	sta		ScreenAdr+10*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+11*FontHeight*BytesPerLine,x
	sta		ScreenAdr+11*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+12*FontHeight*BytesPerLine,x
	sta		ScreenAdr+12*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+13*FontHeight*BytesPerLine,x
	sta		ScreenAdr+13*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+14*FontHeight*BytesPerLine,x
	sta		ScreenAdr+14*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+15*FontHeight*BytesPerLine,x
	sta		ScreenAdr+15*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+16*FontHeight*BytesPerLine,x
	sta		ScreenAdr+16*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+17*FontHeight*BytesPerLine,x
	sta		ScreenAdr+17*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+18*FontHeight*BytesPerLine,x
	sta		ScreenAdr+18*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+19*FontHeight*BytesPerLine,x
	sta		ScreenAdr+19*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+20*FontHeight*BytesPerLine,x
	sta		ScreenAdr+20*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+21*FontHeight*BytesPerLine,x
	sta		ScreenAdr+21*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+22*FontHeight*BytesPerLine,x
	sta		ScreenAdr+22*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
	sta		ScreenAdr+23*FontHeight*BytesPerLine,x			; last line of 192 line display
	sta		ScreenAdr+23*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
.if ScreenHeight = 200
	sta		ScreenAdr+24*FontHeight*BytesPerLine,x			; for 200 line high display
	sta		ScreenAdr+24*FontHeight*BytesPerLine+40*4,x		; since x would overflow to do the job, we do half lines
.endif
	inx
	cpx		#160
	bmi		@nxt
	jmp		@sloop
@nxt:
.endif



	rts
	
	
;**************************************************
;* scroll
;**************************************************
;* scrolls the hi-res text display
;* Copies byte from one row to the next, then copies over that byte, etc... 
;*  and clears bytes in the last line
;**************************************************
scroll:

.if Use65816 = 1
	MOVEMEMN	(ScreenAdr+(BytesPerLine*FontHeight)),ScreenAdr,((BytesPerLine*ScreenHeight)-(BytesPerLine*FontHeight)),0,0

	; clear last line
	ldx		#(BytesPerLine*4)-1
	lda		BGColor
@sloop:
.if ScreenHeight = 192
	sta		ScreenAdr+23*FontHeight*BytesPerLine,x
	sta		ScreenAdr+23*FontHeight*BytesPerLine+BytesPerLine*FontHeight/2,x
.endif

.if ScreenHeight = 200
	sta		ScreenAdr+24*FontHeight*BytesPerLine,x
	sta		ScreenAdr+24*FontHeight*BytesPerLine+BytesPerLine*FontHeight/2,x
.endif
	dex
	bne		@sloop


.else


.if BytesPerLine = 32
	ldx		#0
@sloop:
	lda		ScreenAdr+( 1*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 0*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 2*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 1*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 3*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 2*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 4*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 3*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 5*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 4*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 6*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 5*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 7*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 6*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 8*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 7*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 9*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 8*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(10*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 9*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(11*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(10*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(12*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(11*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(13*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(12*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(14*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(13*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(15*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(14*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(16*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(15*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(17*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(16*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(18*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(17*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(19*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(18*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(20*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(19*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(21*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(20*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(22*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(21*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(23*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(22*FontHeight*BytesPerLine),x
.if ScreenHeight = 200
	lda		ScreenAdr+(24*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(23*FontHeight*BytesPerLine),x
.endif
.if unrollmore = 1
	lda		ScreenAdr+1*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+0*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+2*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+1*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+3*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+2*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+4*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+3*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+5*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+4*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+6*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+5*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+7*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+6*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+8*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+7*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+9*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+8*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+10*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+9*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+11*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+10*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+12*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+11*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+13*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+12*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+14*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+13*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+15*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+14*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+16*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+15*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+17*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+16*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+18*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+17*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+19*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+18*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+20*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+19*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+21*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+20*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+22*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+21*FontHeight*BytesPerLine+1,x
	lda		ScreenAdr+23*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+22*FontHeight*BytesPerLine+1,x
.if ScreenHeight = 200
	lda		ScreenAdr+24*FontHeight*BytesPerLine+1,x
	sta		ScreenAdr+23*FontHeight*BytesPerLine+1,x
.endif
.endif
	lda		BGColor			; clear last line
.if ScreenHeight = 192
	sta		ScreenAdr+23*FontHeight*BytesPerLine,x
.endif
.if ScreenHeight = 200
	sta		ScreenAdr+24*FontHeight*BytesPerLine,x
.endif
.if unrollmore = 1
.if ScreenHeight = 192
	sta		ScreenAdr+23*FontHeight*BytesPerLine+1,x
.endif
.if ScreenHeight = 200
	sta		ScreenAdr+24*FontHeight*BytesPerLine+1,x
.endif
	inx
.endif
	inx
	beq		@nxt
	jmp		@sloop
@nxt:
.endif

.if BytesPerLine = 40
	ldx		#0
@sloop:
	lda		ScreenAdr+( 1*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 0*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 1*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 0*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 2*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 1*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 2*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 1*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 3*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 2*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 3*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 2*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 4*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 3*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 4*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 3*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 5*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 4*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 5*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 4*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 6*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 5*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 6*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 5*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 7*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 6*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 7*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 6*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 8*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 7*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 8*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 7*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+( 9*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 8*FontHeight*BytesPerLine),x
	lda		ScreenAdr+( 9*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 8*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(10*FontHeight*BytesPerLine),x
	sta		ScreenAdr+( 9*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(10*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+( 9*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(11*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(10*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(11*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(10*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(12*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(11*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(12*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(11*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(13*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(12*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(13*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(12*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(14*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(13*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(14*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(13*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(15*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(14*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(15*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(14*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(16*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(15*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(16*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(15*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(17*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(16*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(17*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(16*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(18*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(17*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(18*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(17*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(19*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(18*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(19*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(18*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(20*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(19*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(20*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(19*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(21*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(20*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(21*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(20*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(22*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(21*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(22*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(21*FontHeight*BytesPerLine)+40*4,x
	lda		ScreenAdr+(23*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(22*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(23*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(22*FontHeight*BytesPerLine)+40*4,x
.if ScreenHeight = 192
	lda		BGColor			; clear last line
	sta		ScreenAdr+23*FontHeight*BytesPerLine,x
	sta		ScreenAdr+23*FontHeight*BytesPerLine+40*4,x
.endif

.if ScreenHeight = 200
	lda		ScreenAdr+(24*FontHeight*BytesPerLine),x
	sta		ScreenAdr+(23*FontHeight*BytesPerLine),x
	lda		ScreenAdr+(24*FontHeight*BytesPerLine)+40*4,x
	sta		ScreenAdr+(23*FontHeight*BytesPerLine)+40*4,x
	lda		BGColor			; clear last line
	sta		ScreenAdr+24*FontHeight*BytesPerLine,x
	sta		ScreenAdr+24*FontHeight*BytesPerLine+40*4,x
.endif
	inx
	cpx		#160
	beq		@nxt
	jmp		@sloop
@nxt:
.endif

.endif

	rts


;**************************************************
;* invert_mem
;**************************************************
;*  length contains the length
;**************************************************
invert_mem:
	ldy		#0
nxtaddr:
	lda		(fscreen),y					; get original byte
	eor		#$FF						; invert it
	sta		(fscreen),y					; write it back

	inc16	fscreen
	dec16	length
	bne		nxtaddr
	
	rts
	
	
;**************************************************
;* print_at
;**************************************************
;* Prints a string at a screen location
;* works similar to print@ in Microsoft BASIC
;*  prntat contains @ location
;*  string contains string pointer
;* falls through to _print
;**************************************************
print_at:
	lda		prntat				;
	and		#%00111111			; mask off row bits    (BytesPerLine*2)-1
	sta		col					; save the column
	lda		prntat				; copy LSB
	and		#%11000000			; mask off column bits    254-(BytesPerLine*2)
	asl							; rotate bits into bottom of a
	asl							; rol?
	asl
	sta		row					;
	lda		prntat+1
	asl
	asl
;	clc
	adc		row
	sta		row					; save row info
	
	
;**************************************************
;* print
;**************************************************
;* Prints a zero terminated string at the current x,y location
;*  string contains the string pointer
;* maximum sting length is 256
;**************************************************
print:
	ldy		#0
prn1:
	lda		col
	lsr
	bcs		print1
	;try to print 2 characters at a time
	lda		(string),y
	cmp		#0					; strings are zero terminated
	beq		_printexit
	iny
	lda		(string),y
	dey
	cmp		#0					; strings are zero terminated
	beq		print1a
	; if we get here, we can print 2 characters at once
	sty		ytemp
	jsr		print_642
	ldy		ytemp
	iny
	inc		col
	clc							; branch always
	bcc		print2a				; since we are writing two at once, we know we can't go two past the end of the line
	
print1:
	lda		(string),y			; get a character from the string
	cmp		#0					; strings are zero terminated
	beq		_printexit			; exit if it's a zero

print1a:
	sty		ytemp				; save x
	jsr		print_64			; print the character
	ldy		ytemp				; restore x

	;update column, row, and scroll when needed
print2a:
	inc		col					; next column
	lda		col					; get column
	cmp		#BytesPerLine*2		; BytesPerLine * 2 = characters per line
;	cmp		#64					; 64 chars / line (0-63)
	bcc		_cexit				; is column past the end of a line?

	lda		#0
	sta		col					; set column to zero

	inc		row					; incrament row
	lda		row					; get row
	cmp		#24					; (ScreenHeight/8)	; 24 lines (0-23)
	bcc		_cexit				; branch if row isn't past the end of the screen

	dec		row					; reduce row back to last line

	sty		ytemp				; save x
	jsr		scroll				; scroll the screen
	ldy		ytemp				; restore x

_cexit:	
	iny							; increment the string pointer y
	bne		prn1				; keep printing

	inc		string+1			; update string pointer MSB
	bne		prn1				; keep printing

_printexit:						; we are done
	
	rts

	

No comments:

Post a Comment