[Commodore] Calculate VIC-II byte address of a given point

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
pifu
Posts: 7
Joined: 04 May 2017

[Commodore] Calculate VIC-II byte address of a given point

Post by pifu »

Hello,
I searched around for a compact routine for calculating the VIC-II byte address of a point, given its (x, y) coordinates. As you know, the VIC-II has a weird addressing, i.e. the bitmap addressing in 320x200 graphic mode is not linear: the very first 8 addresses refer to the 8x8-pixel block at top left of the screen, the 2nd ones to the next right block, and so on; so the mapping (x,y) -> address is given by this function:
address(x,y) = 320*row + 8*col + line, where row=int(y/8), col=int(x/col), line=y AND 7.
Most of the routines I found make use of huge tables to precalculate the address; I wrote the routine below, which doesn't waste a lot of space, but is not very fast.
I'll be glad if someone posts a better code, many thanks!

Code: Select all

;Calculate address and mask for a given 320x200-hires point
;address= Base + 320*r + 8*c + l, r=int(y/8), c=int(x/8), l=y&$07
;	= Base + 320*(y>>3) + 8*(x>>3) + y&$07
;	= Base + 256*(y>>3) + 64*(y>>3) + 256*(>x) + x&$F8 + y&$07
;	= Base + 256*(y>>3) + (y>>3:$00)>>2 + 256*(>x) + x&$F8 + y&$07
;so we can access that memory address by a 16-bit pointer as below:
;ptr_h	= >Base + y>>3 + >x + >((y>>3:$00)>>2)
;ptr_l	= <((y>>3:$00)>>2) + y&$07
;Y		= x&$F8 

;	IN:	 X:<x, C:>x, Y:y, .baseh:>Base, .ptr:pointer
;	OUT:	.ptr+Y:address, X:bitmask offset, A:X, C:0, N:0, Z:?, V:?
!macro	COORD .ptr, .baseh {
	TYA				;2
	AND #$07		 ;2	;A = y & 7
	ROL				;2	;save C in bit0 of .ptr, then move it
	ASL				;2	;in bit1 (it'll be RORed out later)
	STA .ptr		 ;3	;.ptr = 0 0 0 y2 y1 y0 >x 0
	TYA				;2
	LSR				;2
	LSR				;2
	LSR				;2
	STA .ptr + 1	;3	;.ptr+1 = y>>3 = 0 0 0 y7 y6 y5 y4 y3
	LSR				;2
	ROR .ptr		 ;5
	LSR				;2	;A= >((y>>3:$00)>>2)=0 0 0 0 0 y7 y6 y5
	ROR .ptr		 ;5	;.ptr = <((y>>3:$00)>>2) + y&7, C = >x
	ADC .ptr + 1	;3	;A = A + y>>3 + >x
	;CLC					 ;C already clear
	ADC #.baseh	 ;2	;A = A + >Base
	STA .ptr + 1	;3	;.ptr+1= >Base+y>>3+>x+>((y>>3:$00)>>2)
	TXA				;2
	AND #$F8		 ;2
	TAY				;2	;Y = x&$F8, (.ptr),Y = address
				  	 ;52 TOT
	;; calculate bitmasks offset
	TXA				;2
	AND #$07		 ;2
	TAX				;2	;X = mask offset
}				  	;58 TOT

; Bitmasks
setmsk	!byte $80, $40, $20, $10, $08, $04, $02, $01
clrmsk	!byte $7F, $BF, $DF, $EF, $F7, $FB, $FD, $FE
User avatar
BB8
Posts: 57
Joined: 01 Nov 2020
Location: Tatooine

Re: [Commodore] Calculate VIC-II byte address of a given poi

Post by BB8 »

This is a Plot function I wrote a few years back.
I didn't compare it to yours yet, I'm just putting it here, but I think there are similarities.

Code: Select all

; ************************************************
;
;       Plot
; 
;       input: _X (word 0-319**)
;              _Y (byte 0-200**)
;       **no boundary check
; 
; offset = BaseAddr + 320*int(Y/8)+(Y and 7) + 8*int(X/8)
; pixel  = 2^(7-(X and 7))
;
; ************************************************
_Plot
        ldy #0          ; 2     ; comput. dY
        sty wOffs       ; 3     ; reset lobyte
        lda _Y          ; 3
        lsr             ; 2
        lsr             ; 2
        lsr             ; 2     ; int(Y/8)
        sta wOffs+1     ; 3     ; 256*int(Y/8) hibyte (lobyte=0)
        lsr             ; 2
        ror wOffs       ; 5
        lsr             ; 2     ; 64*int(Y/8)  hibyte
        ror wOffs       ; 5     ; 64*int(Y/8)  lobyte  (= 320*int(Y/8) lobyte)
        adc wOffs+1     ; 3     ; 256*int(Y/8) + 64*int(Y/8)  hibyte
        sta wOffs+1     ; 3     ; =320*int(Y/8) hibyte
        lda _Y          ; 3     ; add (Y and 7)
        and #7          ; 2
        ora wOffs       ; 3     ; lobyte [xx000xxx]
        sta wOffs       ; 3  48   
 
        lda _X          ; 3     ; dX + dY + BaseAddr
        and #248        ; 2
        adc wOffs       ; 3
        sta wOffs       ; 3
        lda wOffs+1     ; 3
        adc _X+1        ; 3
        adc #>_Vmem     ; 2
        sta wOffs+1     ; 3  22
        
        lda _X          ; 3     ; set pixel-bit
        and #7          ; 2
        tax             ; 2
        lda (wOffs),y   ; 5     
        ora ortab,x     ; 4
        sta (wOffs),y   ; 6  22
 
        rts
 
ortab
        byte 128, 64, 32, 16, 8, 4, 2, 1
wOff, _X, _Y are just some memory locations; _Vmem is the bitmap memory starting address
Post Reply