Help with screen addressing in 6502 Assembler

Basic and Machine Language

Moderator: Moderators

Post Reply
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Help with screen addressing in 6502 Assembler

Post by KingTrode »

H there

Only my 2nd post and I'm needing help already :o

I'm still learning 6502 machine code ATM and wondered is one of the resident guru's could shine some light on my code.

What I am trying to achieve here is take an 8x8 character matrix and display it on screen as a double height magnified x 8 (ie: when a pixel is set an inverse space is displayed x2 one below the other, otherwise a normal space is displayed x2).

Now my code works fine no problem, but struggled to find a way to fit a 8 way loop around my code (for each of the 8 bytes that make up the character - to keep it as small as possible as I am programming with unexpanded VIC in mind) instead of repeating the code block 8 times (well only 7 in the example ATM).

The problem was with adding to the screen address for each successive byte, I just ended up scratching my head.

Thanks in advance for any input

KingTrode

P.S: Sorry about the wonky code formatting, it went all skewed when I pasted it :o

Code: Select all

CHAR_CODE		equ		$01
CHAR_ROM		equ		$8000
PIXEL_ON		equ		96+128
PIXEL_OFF		equ		96
SCREEN_START	equ		$1e00
COLOR_START		equ		$9600
COLOR_CODE		equ		$00
SYS_ADDRESS
				ldx		#$00

BYTE_LOOP		lda		CHAR_ROM + (#CHAR_CODE * #$08),x
				ldy		#$00
BIT_LOOP		pha
				and		#$80
				bne		SET_PIXEL
				lda		#PIXEL_OFF
				jmp		SHOW_PIXEL
SET_PIXEL		lda		#PIXEL_ON
SHOW_PIXEL		sta		SCREEN_START,y
				sta		SCREEN_START+22,y
				lda		#COLOR_CODE
				sta		COLOR_START,y
				sta		COLOR_START+22,y
				pla
				rol
				iny
				cpy		#$08
				bne		BIT_LOOP

				lda		CHAR_ROM + (#CHAR_CODE * $08) +1,x				
				ldy		#$00
BIT_LOOP1		pha
				and		#$80
				bne		SET_PIXEL1
				lda		#PIXEL_OFF
				jmp		SHOW_PIXEL1
SET_PIXEL1		lda		#PIXEL_ON
SHOW_PIXEL1		sta		SCREEN_START+44,y
				sta		SCREEN_START+66,y
				lda		#COLOR_CODE
				sta		COLOR_START+44,y
				sta		COLOR_START+66,y
				pla
				rol
				iny
				cpy		#$08
				bne		BIT_LOOP1

				lda		CHAR_ROM + (#CHAR_CODE * $08) +2,x				
				ldy		#$00
BIT_LOOP2		pha
				and		#$80
				bne		SET_PIXEL2
				lda		#PIXEL_OFF
				jmp		SHOW_PIXEL2
SET_PIXEL2		lda		#PIXEL_ON
SHOW_PIXEL2		sta		SCREEN_START+88,y
				sta		SCREEN_START+110,y
				lda		#COLOR_CODE
				sta		COLOR_START+88,y
				sta		COLOR_START+110,y
				pla
				rol
				iny
				cpy		#$08
				bne		BIT_LOOP2


				lda		CHAR_ROM + (#CHAR_CODE * $08) +3,x				
				ldy		#$00
BIT_LOOP3		pha
				and		#$80
				bne		SET_PIXEL3
				lda		#PIXEL_OFF
				jmp		SHOW_PIXEL3
SET_PIXEL3		lda		#PIXEL_ON
SHOW_PIXEL3		sta		SCREEN_START+132,y
				sta		SCREEN_START+154,y
				lda		#COLOR_CODE
				sta		COLOR_START+132,y
				sta		COLOR_START+154,y
				pla
				rol
				iny
				cpy		#$08
				bne		BIT_LOOP3

				lda		CHAR_ROM + (#CHAR_CODE * $08) +4,x				
				ldy		#$00
BIT_LOOP4		pha
				and		#$80
				bne		SET_PIXEL4
				lda		#PIXEL_OFF
				jmp		SHOW_PIXEL4
SET_PIXEL4		lda		#PIXEL_ON
SHOW_PIXEL4		sta		SCREEN_START+176,y
				sta		SCREEN_START+198,y
				lda		#COLOR_CODE
				sta		COLOR_START+176,y
				sta		COLOR_START+198,y
				pla
				rol
				iny
				cpy		#$08
				bne		BIT_LOOP4

				lda		CHAR_ROM + (#CHAR_CODE * $08) +5,x				
				ldy		#$00
BIT_LOOP5		pha
				and		#$80
				bne		SET_PIXEL5
				lda		#PIXEL_OFF
				jmp		SHOW_PIXEL5
SET_PIXEL5		lda		#PIXEL_ON
SHOW_PIXEL5		sta		SCREEN_START+220,y
				sta		SCREEN_START+242,y
				lda		#COLOR_CODE
				sta		COLOR_START+220,y
				sta		COLOR_START+242,y
				pla
				rol
				iny
				cpy		#$08
				bne		BIT_LOOP5

				lda		CHAR_ROM + (#CHAR_CODE * $08) +6,x				
				ldy		#$00
BIT_LOOP6		pha
				and		#$80
				bne		SET_PIXEL6
				lda		#PIXEL_OFF
				jmp		SHOW_PIXEL6
SET_PIXEL6		lda		#PIXEL_ON
SHOW_PIXEL6		sta		SCREEN_START+264,y
				sta		SCREEN_START+286,y
				lda		#COLOR_CODE
				sta		COLOR_START+264,y
				sta		COLOR_START+286,y
				pla
				rol
				iny
				cpy		#$08
				bne		BIT_LOOP6


FINISHED		rts												; Return to BASIC
User avatar
Mike
Herr VC
Posts: 4846
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

That's what the (),Y address mode is for. ;)

O.K. let's see ...
KingTrode wrote:What I am trying to achieve here is take an 8x8 character matrix and display it on screen as a double height magnified x 8 (ie: when a pixel is set an inverse space is displayed x2 one below the other, otherwise a normal space is displayed x2).
At first, the inner loop:

Code: Select all

; ** Magnify one byte
; $FA contains one byte of the character matrix
; $FB/$FC pointer to odd screen rows
; $FD/$FE pointer to even screen rows
.Inner
 LDY #0
.Inner_00
 ASL $FA
 LDA #32
 BCC Inner_01
 LDA #160
.Inner_01
 STA ($FB),Y
 STA ($FD),Y
 INY
 CPY #8
 BNE Inner_00
 RTS
This needs to be repeated 8 times, reading the byte from the character matrix, and adjusting the pointers in $FB/$FC, and $FD/$FE:

Code: Select all

.Outer
 LDX #0
.Outer_00
 LDA CHAR_ROM + (8 * CHAR_CODE),X
 STA $FA
 JSR Inner
 CLC
 LDA $FB
 ADC #44
 STA $FB
 LDA $FC
 ADC #0
 STA $FC
 CLC
 LDA $FD
 ADC #44
 STA $FD
 LDA $FE
 ADC #0
 STA $FE
 INX
 CPX #8
 BNE Outer_00
 RTS
It only remains to init the pointers:

Code: Select all

.Magnify
 JSR Init ; ** init colour RAM, see below
 LDA #0
 STA $FB
 LDA #22
 STA $FD
 LDA #30
 STA $FC
 STA $FD
 JMP Outer
You can inline the sub-routines to save some bytes.

And the line with 'LDA CHAR_ROM + (8 * CHAR_CODE),X' could be replaced by a more general construct to magnify an arbitrary character.

I'd do the init of the colour RAM with an similar, but extra routine beforehand:

Code: Select all

.Init
 LDA #$00
 STA $FB
 LDA #$96
 STA $FC
 LDX #16
.Init_00
 LDY #0
 LDA #colour
.Init_01
 STA ($FB),Y
 INY
 CPY #8
 BNE Init_01
 CLC
 LDA $FB
 ADC #22
 STA $FB
 LDA $FC
 ADC #0
 STA $FC
 DEX
 BNE Init_00
 RTS
Last edited by Mike on Sat Apr 17, 2010 5:46 am, edited 1 time in total.
Kananga
Vic 20 Afficionado
Posts: 317
Joined: Mon Mar 08, 2010 2:11 pm

Post by Kananga »

Hi Mike, nice solution!
A minor improvement: You can drop the CPY from the inner loop by drawing backwards. And the code is still perfectly readable.

Code: Select all

; ** Magnify one byte
; $FA contains one byte of the character matrix
; $FB/$FC pointer to odd screen rows
; $FD/$FE pointer to even screen rows
.Inner
 LDY #7
.Inner_00
 LSR $FA
 LDA #32
 BCC Inner_01
 LDA #160
.Inner_01
 STA ($FB),Y
 STA ($FD),Y
 DEY
 BPL Inner_00
 RTS
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Post by KingTrode »

Big thanks for the input Mike, much appreciate your time and effort.

Not only have you saved me 190 bytes of precious memory, but also enlightened me on the (),Y address mode. :D

I only started learning 6502 assembler this week, and I'm quite pleased with my progress so far - same with the VIC 20 - not touched one since the early 80's :O

Also thanks Kananga for the alternative Inner loop suggestion :D
Post Reply