Jump to content

BASIC: Load Runlength-encoded Sprite data into VERA RAM


rje
 Share

Recommended Posts

There are two tricks to demonstrate with this code:

(1) the use of VERA's auto-increment when loading sprite data
(2) the use of runlength-encoded data for the X16 logo in 64x64 to save RAM.

 

Here's my code in a nutshell.

175 REM SET UP THE VERA DATA PORT FOR AUTO-INCREMENT AT $04000
180 POKE $9F20,$00
185 POKE $9F21,$40
190 POKE $9F22,16 :REM AUTO-INCREMENT TO 1, HIGH ADDR BIT 0



$9f20 and $9f21 and bit 0 in $9f22 point to the destination address in VERA: in this case, it's $04000.
$9f22 also holds the auto-increment value.  A "16" sets the increment to +1.

 

*** EDIT: The suggestion from the crowd is that it's safer to do all that with a VPOKE %10000, $4000, 0 to set up the target address and the auto-increment.
 

195 REM READ-LOOP
200 READ X, RL :IF X<0 GOTO 750
205 FOR Y=1 TO RL
210 POKE $9F23, X
215 NEXT
220 GOTO 200

The read loop takes advantage of the address setup code, so the inner loop only needs a POKE.

No VPOKE.  No counter to increment.  This doubles the load time, approximately.

The data has the value first, and then the number of cells with this value.  So the read loop has an inner loop that does the actual data assignment.

The runlength count was VERY useful for this data.  Sometimes though, with very colorful icons, it's useless.  Take care.

225 REM
230 REM  X16 LOGO DATA.  FORMAT: VALUE, RUNLENGTH COUNT, ...
235 REM
240 DATA $00,1,$12,1,$AE,1,$91,57,$14,1,$16,1,$14,1,$00,1
245 DATA $12,1,$C9,61,$AE,1,$14,2,$C9,62,$17,1,$C9,5,$16,1
250 DATA $CA,1,$C9,50,$CB,1,$14,1,$91,1,$14,1,$C9,2,$AF,1
255 DATA $C9,5,$CA,1,$E9,1,$16,1,$C9,48,$E7,1,$E9,1,$C9,5
260 DATA $AF,1,$C9,6,$E8,1,$E9,1,$CB,1,$C9,46,$E8,1,$E9,1
265 DATA $E7,1,$C9,5,$AF,1,$C9,6,$E7,1,$E9,2,$E7,1,$C9,43
270 DATA $B5,1,$E8,1,$E9,2,$CA,1,$C9,5,$AF,1,$C9,6,$CA,1
275 DATA $CD,3,$CC,1,$91,1,$C9,40,$CA,1,$CD,4,$C9,6,$AF,1
280 DATA $C9,7,$CC,1,$CD,3,$B0,1,$B5,1,$C9,38,$CA,1,$CC,1
285 DATA $CD,3,$CB,1,$C9,6,$AF,1,$C9,7,$AF,1,$B1,4,$B0,1
290 DATA $AE,1,$C9,36,$B6,1,$B0,1,$B1,4,$AE,1,$C9,6,$AF,1
295 DATA $C9,7,$AE,1,$B8,6,$B6,1,$C9,34,$AF,1,$B8,6,$91,1
300 DATA $C9,6,$AF,1,$C9,8,$B8,7,$B6,1,$C9,31,$91,1,$B7,1
305 DATA $B8,6,$B7,1,$C9,7,$AF,1,$C9,8,$B7,1,$B8,7,$B7,1
310 DATA $C9,29,$B5,1,$B7,1,$B8,7,$B6,1,$C9,7,$AF,1,$C9,8
315 DATA $B6,1,$A2,8,$A1,1,$B5,1,$C9,26,$B5,1,$A2,9,$B5,1
320 DATA $C9,7,$AF,1,$C9,8,$B5,1,$B8,10,$B5,1,$C9,24,$B6,1
325 DATA $B8,10,$C9,8,$AF,1,$C9,9,$B8,11,$AE,1,$C9,22,$B7,1
330 DATA $B8,10,$B7,1,$C9,8,$AF,1,$C9,9,$B7,1,$B9,11,$B6,1
335 DATA $C9,20,$B8,1,$B9,11,$AE,1,$C9,8,$AF,1,$C9,9,$AE,1
340 DATA $9C,12,$9B,1,$C9,17,$B5,1,$B8,1,$9C,12,$C9,9,$AF,1
345 DATA $C9,10,$9C,1,$95,12,$B8,1,$91,1,$C9,14,$AE,1,$9C,1
350 DATA $95,12,$B8,1,$C9,9,$AF,1,$C9,10,$B8,1,$9D,13,$9C,1
355 DATA $B5,1,$C9,12,$B6,1,$95,1,$9D,13,$AF,1,$C9,9,$AF,1
360 DATA $C9,10,$AF,1,$9D,14,$95,1,$AE,1,$C9,10,$93,1,$9D,15
365 DATA $B5,1,$C9,9,$AF,1,$C9,10,$B5,1,$9D,1,$03,14,$9D,1
370 DATA $AF,1,$C9,8,$9B,1,$03,15,$9C,1,$C9,10,$AF,1,$C9,11
375 DATA $9C,1,$03,16,$93,1,$C9,5,$91,1,$9C,1,$03,16,$93,1
380 DATA $C9,10,$AF,1,$C9,11,$AE,1,$9B,1,$95,1,$9D,15,$9A,1
385 DATA $C9,4,$94,1,$9D,15,$9C,1,$9B,1,$B5,1,$C9,10,$AF,1
390 DATA $C9,14,$AE,1,$9A,1,$9B,1,$9C,1,$95,11,$9A,1,$C9,4
395 DATA $9C,1,$95,11,$9C,1,$9B,1,$9A,1,$B5,1,$C9,13,$AF,1
400 DATA $C9,17,$91,1,$92,1,$9B,1,$9C,9,$9A,1,$C9,4,$9B,1
405 DATA $9C,8,$9B,1,$9A,1,$AE,1,$C9,17,$AF,1,$C9,21,$B5,1
410 DATA $9A,1,$9B,1,$9C,5,$9A,1,$C9,4,$9B,1,$9C,5,$9B,1
415 DATA $92,1,$91,1,$C9,20,$AF,1,$C9,24,$99,1,$A3,4,$9A,1
420 DATA $C9,4,$9B,1,$A3,3,$9B,1,$91,1,$C9,23,$AF,1,$C9,24
425 DATA $99,1,$80,4,$99,1,$C9,4,$9A,1,$80,4,$C9,24,$AF,1
430 DATA $C9,24,$99,1,$80,4,$99,1,$C9,4,$7F,1,$80,4,$C9,24
435 DATA $AF,1,$C9,24,$76,1,$7F,4,$7E,1,$C9,4,$7F,5,$C9,24
440 DATA $AF,1,$C9,24,$7E,1,$80,4,$7E,1,$C9,4,$7F,1,$80,3
445 DATA $7F,1,$91,1,$C9,23,$AF,1,$C9,21,$14,1,$62,1,$63,1
450 DATA $64,5,$7E,1,$C9,4,$63,1,$64,5,$7F,1,$5A,1,$91,1
455 DATA $C9,20,$AF,1,$C9,18,$14,1,$62,1,$63,1,$64,8,$62,1
460 DATA $C9,4,$63,1,$64,8,$63,1,$3E,1,$91,1,$C9,17,$AF,1
465 DATA $C9,15,$14,1,$62,1,$64,12,$62,1,$C9,4,$63,1,$64,11
470 DATA $63,1,$3E,1,$14,1,$C9,14,$AF,1,$C9,13,$15,1,$47,1
475 DATA $48,14,$5A,1,$C9,4,$63,1,$48,14,$63,1,$91,1,$C9,12
480 DATA $AF,1,$C9,13,$3F,1,$48,14,$3E,1,$C9,6,$3F,1,$48,14
485 DATA $5A,1,$C9,12,$AF,1,$C9,13,$47,1,$07,12,$48,1,$15,1
490 DATA $C9,8,$46,1,$48,1,$07,12,$46,1,$C9,12,$AF,1,$C9,13
495 DATA $49,12,$48,1,$14,1,$C9,10,$3E,1,$49,12,$47,1,$C9,12
500 DATA $AF,1,$C9,12,$15,1,$49,11,$48,1,$14,1,$C9,12,$15,1
505 DATA $49,11,$48,1,$C9,12,$AF,1,$C9,12,$46,1,$49,10,$47,1
510 DATA $91,1,$C9,14,$14,1,$48,1,$49,10,$14,1,$C9,11,$AF,1
515 DATA $C9,12,$47,1,$49,9,$47,1,$C9,17,$14,1,$48,1,$49,9
520 DATA $3E,1,$C9,11,$AF,1,$C9,12,$08,1,$49,8,$46,1,$C9,20
525 DATA $47,1,$49,8,$46,1,$C9,11,$AF,1,$C9,12,$08,8,$3E,1
530 DATA $C9,22,$46,1,$08,8,$C9,11,$AF,1,$C9,11,$22,1,$2D,6
535 DATA $08,1,$22,1,$C9,24,$2A,1,$08,1,$2D,5,$08,1,$C9,11
540 DATA $AF,1,$C9,11,$2A,1,$2D,5,$08,1,$14,1,$C9,26,$22,1
545 DATA $08,1,$2D,5,$14,1,$C9,10,$AF,1,$C9,11,$2B,1,$2D,4
550 DATA $2C,1,$E5,1,$C9,28,$22,1,$08,1,$2D,4,$22,1,$C9,10
555 DATA $AF,1,$C9,11,$2C,1,$2D,3,$2B,1,$C9,31,$14,1,$2C,1
560 DATA $2D,3,$2B,1,$C9,10,$AF,1,$C9,11,$34,1,$2D,2,$2B,1
565 DATA $C9,33,$E5,1,$2C,1,$2D,2,$2C,1,$C9,10,$AF,1,$C9,10
570 DATA $22,1,$34,2,$2A,1,$C9,36,$2B,1,$34,2,$C9,10,$AF,1
575 DATA $C9,10,$2A,1,$34,1,$22,1,$C9,38,$2B,1,$34,1,$E5,1
580 DATA $C9,9,$AF,1,$C9,10,$2B,1,$22,1,$C9,40,$2A,1,$22,1
585 DATA $C9,9,$AF,1,$C9,63,$AF,1,$C9,63,$AF,1,$C9,63,$AF,1
590 DATA $C9,46,$AE,1,$91,1,$C9,3,$91,1,$AE,1,$C9,10,$AF,1
595 DATA $C9,6,$18,1,$1A,2,$AE,1,$18,1,$1A,1,$19,1,$16,1
600 DATA $17,1,$18,1,$C9,1,$14,1,$19,1,$AE,1,$19,1,$AE,1
605 DATA $C9,1,$17,1,$18,1,$C9,1,$AE,1,$B0,1,$C9,1,$14,1
610 DATA $19,1,$AE,1,$C9,1,$17,2,$1A,2,$17,1,$91,1,$19,1
615 DATA $1A,1,$19,1,$AF,1,$1A,2,$19,1,$AE,1,$1D,1,$AE,1
620 DATA $C9,1,$AE,1,$1D,1,$16,1,$19,1,$14,1,$19,1,$1A,1
625 DATA $19,1,$C9,5,$AF,1,$C9,5,$AE,1,$1B,1,$AE,2,$AF,1
630 DATA $1A,1,$AE,2,$1C,3,$B5,1,$19,1,$1D,1,$18,1,$1D,1
635 DATA $1A,1,$91,1,$1C,2,$C9,1,$1C,1,$1A,1,$17,1,$AE,1
640 DATA $1C,2,$91,1,$1B,2,$16,1,$AE,1,$1C,1,$19,1,$1A,1
645 DATA $17,2,$19,1,$18,1,$AE,1,$1B,1,$AE,1,$1C,1,$1E,1
650 DATA $16,1,$1E,1,$1B,1,$C9,1,$1C,1,$19,1,$1A,1,$AF,1
655 DATA $16,1,$C9,5,$AF,1,$C9,5,$AE,1,$1A,1,$C9,2,$AF,1
660 DATA $19,1,$C9,1,$91,1,$1C,1,$1B,1,$17,1,$19,1,$1C,1
665 DATA $19,1,$18,1,$1A,1,$1C,1,$19,1,$18,1,$1B,1,$AF,1
670 DATA $1D,1,$19,1,$1D,1,$16,1,$1A,1,$18,1,$1A,1,$1B,2
675 DATA $B5,1,$C9,1,$1C,1,$19,1,$1B,1,$18,2,$19,1,$1C,1
680 DATA $1B,1,$1D,1,$91,1,$B5,1,$1A,1,$19,1,$1A,1,$91,1
685 DATA $C9,1,$1B,1,$19,1,$1A,1,$17,1,$1C,1,$91,1,$C9,4
690 DATA $AF,1,$C9,5,$91,1,$1B,3,$16,1,$1B,3,$18,1,$19,1
695 DATA $C9,1,$1A,1,$17,2,$AF,1,$18,1,$AF,1,$1B,1,$91,1
700 DATA $19,1,$1A,1,$AE,1,$B5,1,$18,1,$17,1,$18,1,$C9,1
705 DATA $19,3,$1B,2,$19,1,$AE,1,$1B,3,$18,1,$AE,1,$C9,1
710 DATA $1A,1,$14,1,$1C,1,$1B,1,$91,1,$1B,2,$C9,1,$19,1
715 DATA $AE,1,$1B,3,$C9,5,$AF,1,$C9,47,$18,1,$C9,3,$18,1
720 DATA $C9,11,$17,1,$AE,1,$C9,62,$17,1,$13,1,$14,1,$C9,60
725 DATA $16,1,$14,1,$00,1,$14,1,$16,58,$AF,1,$17,1,$14,1
730 DATA -1,-1 :REM TRIGGERS READ-LOOP END

That's it.

Edited by rje
Link to comment
Share on other sites

40 minutes ago, Lorin Millsap said:

You should be using VPOKE.

Yeah, fiddling with the registers directly isn't perfectly safe.

But how does VPOKE handle auto-increment?  (Because it doesn't out of the box...) I didn't see documentation on VPOKE DOES AUTO-INC.  Only the VERA doc talks about auto-increment, while only the "Programmer's Reference" talks about VPOKE.  We need some bridging documentation...

Edited by rje
Link to comment
Share on other sites

4 hours ago, rje said:

Yeah, fiddling with the registers directly isn't perfectly safe.

But how does VPOKE handle auto-increment?  (Because it doesn't out of the box...) I didn't see documentation on VPOKE DOES AUTO-INC.  Only the VERA doc talks about auto-increment, while only the "Programmer's Reference" talks about VPOKE.  We need some bridging documentation...

Actually, I don't think you could use VPOKE in this instance.  Under the hood, VPOKE simply sets the address at $9f20-$9f22 and pokes the value into $9f23. Theoretically, you could set the first argument, the bank, to 16 to set the increment bit, since it's just poking that value to $9f22. However, the incrementing wouldn't work with calling VPOKE continuously since it's explicitly setting the address each time.  I just tried it with an experiment and it didn't seem to increment. You could probably use VPOKE for the first piece of data though, to set the address, and just poke to $9f23 after that. It should in theory be a tiny bit faster since the setting up of the address is being done in assembly instead of BASIC. Less lines of code too.

Edited by Ender
  • Thanks 1
Link to comment
Share on other sites

Thanks Ender - I might try that.  Perhaps the VPOKE's first argument sets ALL of $9f22?  So I could VPOKE $16, $4000, data?  Sounds dangerous...

 

(Sorry: I meant VPOKE $10, $4000, data)

Edited by rje
Link to comment
Share on other sites

1 minute ago, rje said:

Thanks Ender - I might try that.  Perhaps the VPOKE's first argument sets ALL of $9f22?  So I could VPOKE $16, $4000, data?  Sounds dangerous...

Yup, it just takes the value of the first argument and stores it into $9f22.  (Though I think it would be decimal 16, not hex). Actually, taking a closer look at your code, it might not be less lines of code, given the way you're doing runlength.

  • Thanks 1
Link to comment
Share on other sites

D'oh, yes, but you got my drift.  I was getting excited.

 

I can replace three of those set-up lines with a single:

VPOKE %10000, $4000, 0

 

And yeah, that works!  Thanks!

Edited by rje
  • Like 1
Link to comment
Share on other sites

Your RLE format is somewhat hungry for memory space 😀.

I'd use a [RunLength], [Value] format where RunLength's MSB indicates whether it's followed by a single byte value that is repeated N times, or by N bytes that are only used once.

So, a data stream that looks like ABCDDDDDDDEFGHIJJJJJJ would be stored as 3,A,B,C,135,D,5,E,F,G,H,I,134,J for a total of 14 values, while your format would be A,1,B,1,C,1,D,7,E,1,F,1,G,1,H,1,I,1,J,6 for a total of 20 values. The difference would be even greater if there are many non-repeated values.

Of course, this could be extended to indicate, for instance, that what follows is a pattern of M values that should be repeated N times, by using a few bits of the RunLength byte.

  • Like 2
Link to comment
Share on other sites

8 hours ago, Guybrush said:

Your RLE format is somewhat hungry for memory space 😀.

I'd use a [RunLength], [Value] format where RunLength's MSB indicates whether it's followed by a single byte value that is repeated N times, or by N bytes that are only used once.

So, a data stream that looks like ABCDDDDDDDEFGHIJJJJJJ would be stored as 3,A,B,C,135,D,5,E,F,G,H,I,134,J for a total of 14 values, while your format would be A,1,B,1,C,1,D,7,E,1,F,1,G,1,H,1,I,1,J,6 for a total of 20 values. The difference would be even greater if there are many non-repeated values.

Of course, this could be extended to indicate, for instance, that what follows is a pattern of M values that should be repeated N times, by using a few bits of the RunLength byte.

That's a useful tip. I did my own RLE expander in assembly, and while I didn't think to do that, I'm totally going to add it.

Link to comment
Share on other sites

51 minutes ago, StephenHorn said:

That's a useful tip. I did my own RLE expander in assembly, and while I didn't think to do that, I'm totally going to add it.

Yeah, it's really much better suited for assembly since you can simply test the MSB with BPL or BMI after loading.

Link to comment
Share on other sites

An excellent upgrade suggestion, Guy, thank you.  As you can see from the data, there are several instances where that tweak would shrink the data size.

...sure enough, it trims 16 full lines of code, or (very roughly) about 1K.  As an example, here are the first four lines of the improved runlength encoding, which almost handle the first five lines of the old encoding.  So I predict it's around 16% more efficient.

240 DATA 3,$00,$12,$ae,185,$91,5,$14,$16,$14,$00,$12,189,$c9,1,$ae
245 DATA 130,$14,0,190,$c9,1,$17,133,$c9,2,$16,$ca,178,$c9,4,$cb
250 DATA $14,$91,$14,130,$c9,1,$af,133,$c9,3,$ca,$e9,$16,176,$c9,2
255 DATA $e7,$e9,133,$c9,1,$af,134,$c9,3,$e8,$e9,$cb,174,$c9,3,$e8

 

Edited by rje
Link to comment
Share on other sites

On 1/15/2021 at 1:21 AM, rje said:

But how does VPOKE handle auto-increment?  (Because it doesn't out of the box...)

I always thought VPOKE should handle auto-increment, but I never tried. I understood it that way after David's video, where he described auto-increment feature. Do you think it's by design? Looks more like a bug or not implemented yet thing to me?

Link to comment
Share on other sites

I always thought VPOKE should handle auto-increment, but I never tried. I understood it that way after David's video, where he described auto-increment feature. Do you think it's by design? Looks more like a bug or not implemented yet thing to me?

No, VPOKE is not meant to take advantage of auto increment. VPOKE more fully takes advantage of direct access, but for speed once you set up auto increment you would just keep poking additional values. So if you are sending a sequence you would enable auto increment then VPOKE the first byte in the sequence and POKE the rest.


Sent from my iPhone using Tapatalk
  • Thanks 2
Link to comment
Share on other sites

44 minutes ago, Lorin Millsap said:

No, VPOKE is not meant to take advantage of auto increment. VPOKE more fully takes advantage of direct access, but for speed once you set up auto increment you would just keep poking additional values. So if you are sending a sequence you would enable auto increment then VPOKE the first byte in the sequence and POKE the rest.

Now after your explanation and rethinking this myself it became logical and simple. I feel myself stupid now. ) Thank you for clarifying!

Edited by Cyber
I actually confused the purpose if direct access with special task register. It got mixed up in my head. Now it's clear.
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

Please review our Terms of Use