128x128 fast Bitmap Screen

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

128x128 fast Bitmap Screen

Post by MrSterlingBS »

Dear all,

i have implemented a fast 128x128 Bitmap Screen. < 50 cycles per pixel.
But i need an 184x176 Bitmap screen with the same speed if it possible.
The example code is partly from Codebase64.

Is there anybody outhere he can help me?

My goal is to write an own SuperExpander with some mathematicals function to draw on the screen in pure assembler.


Best regards
Sven

PS: the time measurement can be deleted, of course.

Code: Select all

; 10 SYS8192

*=$1201
        dB    $0B, $12, $0A, $00, $9E, $38, $31, $39, $32, $00, $00, $00
*=$2000

		;sei		; can be enabled, but then you can not measuring the time
init:
		
; set up screen bitmap (192x160 pixels)
        LDA #%00010101          ; 20 lines and double char (y=160 pixel) 
        STA $9003
        LDA #24                 ; 24 columns (x=192 pixel)
        STA $9002
        LDA #204                ; 4096 screen, 4096 charmap
        STA $9005
        LDA #10					; Make place for more columns
        STA $9000               
		lda #$26				; center screen if necessary
		sta $9001
		
		lda #$05				; color of dot´s
		sta $20		
		
		lda #16					; first character, we need 256 - 16 = 240 for the whole screen
		sta $21

		ldx #$00
LoopCharMap:		
		lda $21
		sta $1000+(0*24),x
		lda $20
		sta $9400+(0*24),x
		inc $21
		lda $21
		sta $1000+(1*24),x
		lda $20
		sta $9400+(1*24),x
		inc $21
		lda $21
		sta $1000+(2*24),x
		lda $20
		sta $9400+(2*24),x
		inc $21
		lda $21
		sta $1000+(3*24),x
		lda $20
		sta $9400+(3*24),x
		inc $21
		lda $21
		sta $1000+(4*24),x
		lda $20
		sta $9400+(4*24),x
		inc $21
		lda $21
		sta $1000+(5*24),x
		lda $20
		sta $9400+(5*24),x
		inc $21
		lda $21
		sta $1000+(6*24),x
		lda $20
		sta $9400+(6*24),x
		inc $21
		lda $21
		sta $1000+(7*24),x
		lda $20
		sta $9400+(7*24),x
			
		inc $21
		
		inx
		cpx #$10
		bne LoopCharMap		
		
Cleanupbitmap:
        LDA #$00
        STA $02
        LDX #$11        ; Bitmap start $1100
        LDA #0
ilpe2:   
		STX $03
        TAY
ilp3:   
		DEY
        STA ($02),Y
        BNE ilp3
        INX
        CPX #$20
        BNE ilpe2
		
	lda #0
	sta $A1
	sta $A2
		
		ldy #0			; Max 0 - 127
LoopY:
		ldx #0			; Max 0 - 127
LoopX:
		jsr SPlot
		inx
		cpx #127
		bne LoopX
		
		iny
		cpy #127
		bne LoopY
		
	lda $a2				; save the jiffies for correct timing
	sta $30
	lda $a1
	sta $31
		
		lda #46			; reset screen to normal settings
		sta $9003
		lda #22
		sta $9002
		lda #192
		sta $9005
		lda #12
		sta $9000
		
		jsr $e55f		; clear screen
			
		
	lda $30
	tax
	lda $31
	jmp $ddcd			; print solution of jiffies
	
	
SPlot:
		lda LoByte,x	;		4*
		sta $FB			; ZP	3	
		lda HiByte,x	;		4*
		sta $FC			; ZP	3	
		lda ($FB),y		;		5*
		ora BitMask,x	;		4*
		sta ($FB),y		;		6
		rts				;		6
						;	--------
						;	   31	cycles
		
		
LoByte:
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 1-2		Pixel  0-15
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 3-4		Pixel 16-31
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 5-6		Pixel 32-47
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 7-8		Pixel 48-63
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 9-10		Pixel 64-79
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 11-12		Pixel 80-95
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 13-14		Pixel 96-111
		db $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80		; Column 15-16		Pixel 112-127
				
HiByte:
		db $11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11		; Column 1-2		...
		db $12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12,$12		; Column 3-4
		db $13,$13,$13,$13,$13,$13,$13,$13,$13,$13,$13,$13,$13,$13,$13,$13		; Column 5-6
		db $14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14,$14		; Column 7-8
		db $15,$15,$15,$15,$15,$15,$15,$15,$15,$15,$15,$15,$15,$15,$15,$15		; Column 9-10
		db $16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16,$16		; Column 11-12
		db $17,$17,$17,$17,$17,$17,$17,$17,$17,$17,$17,$17,$17,$17,$17,$17		; Column 13-14
		db $18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18,$18		; Column 15-16
		
BitMask:
		db $80,$40,$20,$10,$08,$04,$02,$01	; #%100000000, #%01000000, #%00100000, ...
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
		db $80,$40,$20,$10,$08,$04,$02,$01
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: 128x128 fast Bitmap Screen

Post by Mike »

For the 128x128 resolution, you might consider putting the text screen at $1800, so the start character can be $00 and the bitmap then spans $1000..$17FF instead. Also, the setup code for the text screen could be streamlined a lot (still assuming a column-wise layout, of course).
MrSterlingBS wrote:i need an 184x176 Bitmap screen with the same speed if it possible.
A 184x176 pixel bitmap could be realised with 23 columns and 11 rows with double-height characters, but ...

... the VIC chip can only access the character ROM and internal RAM. External expansions (regardless whether RAM or ROM) are not visible, especially not the +3K RAM area - even though there exist register values for $9005 that would suggest so. With aforementioned layout, the bitmap nearly fills the complete "upper" 4K ($1000..$1FFF), with 4048 bytes. You would have to put the address generating text screen at either $0000 or $0200, neither of which is especially useful when trying to use that bitmap for anything other than just displaying a static picture.

If what you wanted actually is 176x184 pixels with 22 columns and 23 (single-height character) rows resembling the original dimensions of the VIC-20 text screen, that one is extremely inconvenient to realise because of its odd number of rows. You would need to resort to single-height characters and as they only span half the bitmap size, you need to install a "raster IRQ" (with the VIA timers) mid-screen to change the character base. Keeping up that display during disk I/O is just a PITA. Again, the text screen would have to go into the "lower" 1K.
< 50 cycles per pixel.
For single pixel plots, this is about what can be rightfully expected, provided the characters are arranged column-wise. Then it is a simple look-up of the column start address from the X co-ordinate, using the (ZP),Y address mode to access the bitmap - even though I would prefer to keep the tables small (like, 20 low bytes and 20 high bytes for the column addresses, 8 or 16 bytes for the mask bytes), which costs some extra shift and mask instructions.

A fast line drawing routine avoids re-calculating the address for every pixel and then easily runs at ~30000 pixels/second, which translates to ~32 cycles/pixel. 8)
My goal is to write an own SuperExpander with some mathematicals function to draw on the screen in pure assembler.
If that tool is supposed to interoperate with the OS, chances are that you ultimately end up with something resembling MINIGRAFIK ... ;) ... with 160x192 as preferred resolution, for very much the reasons I stated above. Any higher resolution is unsuitable for daily business.
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: 128x128 fast Bitmap Screen

Post by MrSterlingBS »

Mike wrote:With aforementioned layout, the bitmap nearly fills the complete "upper" 4K ($1000..$1FFF), with 4048 bytes.
Then we have a 4k Screen. :mrgreen:

(mod: quote repaired)
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: 128x128 fast Bitmap Screen

Post by MrSterlingBS »

If i putting the text screen at $1800, and the start character in each column is at $00 then i can delete the lowbyte table and use LDA #00 / STA $FB in each pixel calculation. Right? This saves 2 cycles and a lot of bytes…
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: 128x128 fast Bitmap Screen

Post by Mike »

You probably are confusing the low-byte values of the column addresses with the byte value of the top-left character.

What I was referring to as setup routine that could be streamlined is the part that contains the loop labeled "LoopCharMap". Repeatedly fetching the byte value from zero page instead of keeping it in the Accumulator, doing a INC on that zero page value, and intermixing the setup of text and colour RAM leads to a rather cumbersome construction.

For comparison, here is the loop that sets up the text screen in the @ON command of MINIGRAFIK:

Code: Select all

.On
 CLC
 LDA #$10
 TAY
.On_00
 STA $0FF0,Y
 ADC #$0C
 BCC On_01
 SBC #$EF
.On_01
 INY
 BNE On_00
 [...]
MrSterlingBS wrote:[...] delete the lowbyte table and use LDA #00 / STA $FB in each pixel calculation.
If you want to eliminate updating the low-byte of those column addresses, you have to put the bitmap columns at $yy80..$yyFF (with $yy = $10..$1F) as the text screen can only be placed at $xx00 addresses (with $xx even). As the text screen itself only needs 128 double-height characters, this works out and you can quite as well leave it at $1000. You would then use characters 8..15, 24..31, ..., 248..255 for the columns. This leaves you with a 'fragmented' memory layout, where $1100..$117F, $1200..$127F, ..., $1F00..$1F7F are unused. Keeping the low-byte of the column address constant then saves 7 cycles (4 for the LDA low_table,X instruction, 3 for the STA low instruction).

As I wrote in my previous post, non-trivial graphics algorithms avoid re-calculating the bitmap byte address for each access - or they anyhow spend comparatively more time within calculations, so pixel access time is only a smaller fraction of the total time. I already mentioned the line drawing routine. An ellipse drawing routine that also is in my repository draws around 4000 pixels/second, which translates to ~250 cycles/pixel. It actually recalculates the bitmap addresses for each pixel. However, saving 7 cycles there merely amounts to a 3% speed up which probably is too small to be noticed.
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: 128x128 fast Bitmap Screen

Post by MrSterlingBS »

Dear Mike,

thanks again. I know your Minigrafik is one of the best solution in the forum (world?).
But, I would also like to understand how the program works.
And the best way is to code by myself.

Sorry for the stupid questions.

Your code (@ON) to prepare the screen looks very elegant.
I'm trying to implement it in my code.

Best reagrds,
Sven

:D Coding VIC 6502 is fun.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: 128x128 fast Bitmap Screen

Post by Mike »

MrSterlingBS wrote:But, I would also like to understand how the program works. And the best way is to code by myself.
Nothing wrong about that, but then one of the first things you should work on is bringing code and comments in line.

What you have got is a 128x128 bitmap in the top-left corner of what originally was a 192x160 bitmap display. This makes sub-optimal use of the $1000..$1FFF memory range for graphics display, even more so if you decide to adopt the fragmented layout for a constant low-byte of the column address. There is hardly any use for those fifteen empty 128 byte snippets that result from that layout.

I do not see any substantial speed advantage of 128x128 pixels over a 160x192 (or 192x160) pixel bitmap. Sticking to a 128x128 layout should not result in wasted memory. Having the bitmap in $1000..$17FF and the text screen in $1800..$187F (which is what I suggested in my initial response) at least leaves contiguous memory in $1880..$1FFF which is a lot easier to be used for something else.

The setup code for the VIC registers could also be much improved to make it TV system neutral. At the moment, it is hardcoded for PAL values.
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: 128x128 fast Bitmap Screen

Post by MrSterlingBS »

Dear Mike,

after our discussion and some reflection, I also come to the conclusion to leave the screen at 192x160.
I had used the 128x128 screen before because I hadn't quite figured out the memory management yet.

(The 192x160 screen layout was borrowed from a code from the net and is that what i am searching for
when I started to deal with pixel graphics.)

Trying to get the "dot engine" running on both systems, PAL and NTSC, is a next step.


Best regards
Sven
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: 128x128 fast Bitmap Screen

Post by Mike »

You are aware that the individual pixels are not square but horizontally elongated?

The 192x160 resolution results in a display window that is twice as wide as it is high. With 160x192 pixels, you get a display window that has a standard 4:3 size ratio.

Of course it all depends on the application you have in mind, but I wanted to note this just in case you assumed the 160x192 resolution would result in a upright/portrait display.
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: 128x128 fast Bitmap Screen

Post by MrSterlingBS »

Dear Mike,

that is an important information and i forgot that during the coding.
I read in a book or the internet the size in µm of a dot. I dont remember.
Then we have a better illustration with 160 by 192 pixels.

Check!

For the Screen Init i use now:

Code: Select all

LDA #%00110001        ; 24 lines and double char (y=192 pixel) 
STA $9003			; Poke 36867,49
LDA #20                 	; 20 columns (x=160 pixel)
STA $9002			; Poke 36866,20
And of course som corrections in x-y...

The picture looks much better.

I like to use this fast dot routine to draw some mathematical functions like f(x) = 2*x^2+sin(x)
And do not like to use your minigrafik, this is your baby. And i like to use the KERNAL routines SIN, TAN, etc.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: 128x128 fast Bitmap Screen

Post by Mike »

MrSterlingBS wrote:And do not like to use your minigrafik, this is your baby.
One of the specific reasons I wrote MINIGRAFIK was so people could easily do hires graphics on the VIC-20 without the need to wrap their head around the nitty-gritty details.
And i like to use the KERNAL routines SIN, TAN, etc.
MINIGRAFIK does not hinder you in doing that.
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: 128x128 fast Bitmap Screen

Post by MrSterlingBS »

Hello everybody,

here is a new version of my 128x128 fast plot routine.
Now, with some ideas from Mike, the routine is faster and has no tables.

Only the arrangement of the characters I have not programmed optimally.
Is there anyone who can improve the routine? I would be very grateful for
help and a little explanation.
Unfortunately, I couldn't implement Mike's routine from this post, I don't understand it 100%.

Have a nice day
Sven


Code: Select all

; 10 SYS8192

*=$1201
        	dB	$0B, $12, $0A, $00, $9E
		dB	$38, $31, $39, $32			; SYS8192 = $2000
		dB	$00, $00, $00
*=$2000

       
init:
		SEI					; disable interrupt
		
; set up screen bitmap (128x128 pixels)

        LDA #%00010001          		; 8 lines as double char (y=128 pixel) 
        STA $9003					; details of Bit setting see MASTERING the VIC-20
        LDA #16                			; 16 columns (x=128 pixel)
        STA $9002
        LDA #204                			; $1000-107F screen, $1080-1FFF Bitmap
        STA $9005
		
	lda #$0A				
	sta $900f					; change the color of border and screen
    
        LDX #16
ilp1:
        LDA #06					; color of pixel
        STA $93f0,X             
        INX
	cpx #144
        BNE ilp1
		
; Clean up bitmap:
        LDA #$00
        STA $02
        LDX #$10        				; Bitmap start $1080
ilpe2:   
	STX $03
        TAY
ilp3:   
	DEY
        STA ($02),Y
        BNE ilp3
        INX
        CPX #$20
        BNE ilpe2
		
		ldx #0
		clc
		lda #8
LoopScreenMap:
		sta $1000,x
		adc #1
		sta $1010,x
		adc #1
		sta $1020,x
		adc #1
		sta $1030,x
		adc #1
		sta $1040,x
		adc #1
		sta $1050,x
		adc #1
		sta $1060,x
		adc #1
		sta $1070,x
		adc #9 
		inx
		cpx #16
		bne LoopScreenMap
		
		ldx #$80				; this code snippet is from MASTERING the VIC-20
		clc					; updated to this version
		lda #$80
Power:
		sta $1080,x			; copy the power table to free memory location $1100 - $117F
		ror					; rotate all bits one right 128, 64, 32, 16, 8, 4, 2, 1
		bcc SkipPower		
		ror
SkipPower:
		inx
		bne Power
		
		
Loop2:						; this code snippet is from CODEBASE64
		ldy #$07				; https://codebase64.org/doku.php?id=base:dots_and_plots
SMC1:
		lda #$10
		sta $1200,x
		inx
		dey
		bpl SMC1
		inc SMC1+1
		clc
		adc #$40
		bcc Skip2
        	inc SMC1+1
Skip2:
		cpx #8*16
		bne Loop2
		
		
		lda #$80				; the idea is from Mike and saves 7 cycles per plot
		sta $fb				; load lowbyte value to ZP $FB
		
		ldx #0
LoopX:
		ldy #63
	
		lda $1200,x			; load highbyte from generated table
		
		sta $fc
			
		lda ($fb),y
		ora $1100,x			; load x-bit from table
		sta ($fb),y
		inx
		cpx #127+1
		bne loopX
		
		lda #%10000000			; some points to test the routine
		sta $1080				; x=0; y=0,127
		sta $10FF
		
		lda #%00000001
		sta $1F80				; x=127, y=0,127
		sta $1FFF
		
				
		
waitkey:
        	jmp waitkey        
 			
		
Post Reply