Pattern autoincrementing - or not?

The Speccy's spritely young offspring. Discuss everything from FPGA to ZX
Post Reply
User avatar
Spud
Manic Miner
Posts: 375
Joined: Sun Nov 12, 2017 8:50 pm
Contact:

Pattern autoincrementing - or not?

Post by Spud »

I was intending to wait until I have a Next in my grubby mits before attempting to code for it, but screw that if I have to wait another year!

So I'm porting something from SAM Coupé as my first foray into it as all the game logic will stay the same amd I just need to rewrite some platform specific code. Sees a quick win.

The 4-bit sprites on the Next are analogous to SAM's mode 4 screen format, 4 bit per pixel, 16 colours so it makes it even easier. But I seem to have a problem writing out the patterns.

The guidence at https://www.specnext.com/sprites/ says:
Port 0x5B (W)

Once a pattern number is selected via port 0x303B, the 256-byte or 128-byte pattern can be written to this port. The internal pattern pointer auto-increments after each write so as many sequential patterns as desired can be written. The internal pattern pointer will roll over from pattern 127 to pattern 0 (4-bit patterns) or from pattern 63 to pattern 0 (8-bit patterns) automatically.
So I take it this means I can just select sprite pattern 0 and then squirt out the data, right, and if I send say 256 bytes (to represent two patterns worth of 4 bit per pixel sprites) then it should automatically put the first 128 bytes i Pattern 0 and the second 128 bytes into Pattern 1?
It doens't work for me. Pattern 0 is fine, Pattern 1 is a corrupt mess. This is the code:

Code: Select all

        ld bc,$303b   ; this sprite control port again
        xor a        ; first sprite
        out (c),a   ; select it
        ld hl, tiles ; 16 tile graphics stored here
        ld c,$5b      ; copying sprite data goes via this port apparently
        ld b,0      ; 2 sprites worth
        otir
If I split it into two discrete chunks:

Code: Select all

        ld bc,$303b   ; this sprite control port again
        ld a,0        ; first sprite
        out (c),a     ; select it
        ld hl, tiles ; first tile graphic
        ld c,$5b      ; copying sprite data goes via this port
        ld b,128      ; 128 bytes, 1 sprite pattern
        otir

        ld bc,$303b   ; this sprite control port again
        ld a,1        ; first sprite
        out (c),a     ; select it
        ld hl, tiles+128 ; second tile graphic
        ld c,$5b      ; copying sprite data goes via this port
        ld b,128        ; 128 bytes, another sprite pattern
        otir
it works. Did I misunderstand how writing out the pattern data and autoincrementing them works? I suppose it doens't matter if the latter works but I was hoping I could save some typing.

Thanks for reading this far if you did :-)
AndyC
Dynamite Dan
Posts: 1409
Joined: Mon Nov 13, 2017 5:12 am

Re: Pattern autoincrementing - or not?

Post by AndyC »

OTIR puts BC onto the address bus as the IO address (like most Z80 IO instructions), so it really only works fully on machines that only decode the lower 8-bits of the address bus unless you are very careful about what values are in B and how they'll affect the output.
dfzx
Manic Miner
Posts: 683
Joined: Mon Nov 13, 2017 6:55 pm
Location: New Forest, UK
Contact:

Re: Pattern autoincrementing - or not?

Post by dfzx »

Spud wrote: Wed Apr 06, 2022 12:20 am I was intending to wait until I have a Next in my grubby mits before attempting to code for it, but screw that if I have to wait another year!
Can't help with your query, but amen to that sentiment! I've been diligently holding off doing any Next development until I have one, but I don't want to wait another year.
Derek Fountain, author of the ZX Spectrum C Programmer's Getting Started Guide and various open source games, hardware and other projects, including an IF1 and ZX Microdrive emulator.
Alcoholics Anonymous
Microbot
Posts: 194
Joined: Mon Oct 08, 2018 3:36 am

Re: Pattern autoincrementing - or not?

Post by Alcoholics Anonymous »

Spud wrote: Wed Apr 06, 2022 12:20 am Pattern 0 is fine, Pattern 1 is a corrupt mess. This is the code:

Code: Select all

        ld bc,$303b   ; this sprite control port again
        xor a        ; first sprite
        out (c),a   ; select it
        ld hl, tiles ; 16 tile graphics stored here
        ld c,$5b      ; copying sprite data goes via this port apparently
        ld b,0      ; 2 sprites worth
        otir
If I split it into two discrete chunks:

Code: Select all

        ld bc,$303b   ; this sprite control port again
        ld a,0        ; first sprite
        out (c),a     ; select it
        ld hl, tiles ; first tile graphic
        ld c,$5b      ; copying sprite data goes via this port
        ld b,128      ; 128 bytes, 1 sprite pattern
        otir

        ld bc,$303b   ; this sprite control port again
        ld a,1        ; first sprite
        out (c),a     ; select it
        ld hl, tiles+128 ; second tile graphic
        ld c,$5b      ; copying sprite data goes via this port
        ld b,128        ; 128 bytes, another sprite pattern
        otir
What you're thinking is correct but you're code in the two snippets above are not actually doing the same thing.

The pattern number (or memory address in pattern memory) is actually "N N N N N N N6" (times 128 for memory address) with N6 the least significant bit. Why is N6 the least significant bit? Because of backward compatibility (yeah backwards compatibility was an issue on a machine that wasn't even released yet :D ). At one point there were only 8-bit sprites with pattern numbers 0-63 "NNNNNN". The introduction of 4-bit meant another lower significant bit was needed to divide the 256-byte patterns in two but it couldn't be put in bit 0. You can also think of the "NNNNNN" as selecting a 256-byte pattern 0-63 and then N6 indexing halfway in to the 128th byte if set.

So in the first one you are doing what you intended, filling the first 256 bytes of pattern memory with two 4bit sprite images in slots 0,1. That's equivalent to one 8bit sprite image occupying the same space.

In the second one you are putting the first image in slot 0 ("0000000") and the second in slot 2 ("0000010"), N6=0 both times.

As the first one was correctly filling pattern memory but didn't display properly, I think you probably have the second sprite pointing at the wrong pattern in its attributes.
Alcoholics Anonymous
Microbot
Posts: 194
Joined: Mon Oct 08, 2018 3:36 am

Re: Pattern autoincrementing - or not?

Post by Alcoholics Anonymous »

dfzx wrote: Wed Apr 06, 2022 10:31 am Can't help with your query, but amen to that sentiment! I've been diligently holding off doing any Next development until I have one, but I don't want to wait another year.
There is a lot to the Next. I highly recommend becoming familiar now -- the emulators are partial but they do implement most common things and can be used to play around.
User avatar
Spud
Manic Miner
Posts: 375
Joined: Sun Nov 12, 2017 8:50 pm
Contact:

Re: Pattern autoincrementing - or not?

Post by Spud »

Alcoholics Anonymous wrote: Thu Apr 07, 2022 4:34 am
What you're thinking is correct but you're code in the two snippets above are not actually doing the same thing.

The pattern number (or memory address in pattern memory) is actually "N N N N N N N6" (times 128 for memory address) with N6 the least significant bit. Why is N6 the least significant bit? Because of backward compatibility (yeah backwards compatibility was an issue on a machine that wasn't even released yet :D ). At one point there were only 8-bit sprites with pattern numbers 0-63 "NNNNNN". The introduction of 4-bit meant another lower significant bit was needed to divide the 256-byte patterns in two but it couldn't be put in bit 0. You can also think of the "NNNNNN" as selecting a 256-byte pattern 0-63 and then N6 indexing halfway in to the 128th byte if set.

So in the first one you are doing what you intended, filling the first 256 bytes of pattern memory with two 4bit sprite images in slots 0,1. That's equivalent to one 8bit sprite image occupying the same space.

In the second one you are putting the first image in slot 0 ("0000000") and the second in slot 2 ("0000010"), N6=0 both times.

As the first one was correctly filling pattern memory but didn't display properly, I think you probably have the second sprite pointing at the wrong pattern in its attributes.
Bingo! I was selecting the 4th pattern rather than the 2nd :) (N6 bit was set alongside setting the pattern to 1 in the previous attribute) Thank you!!
Post Reply