30-column 8x2 multicolor (even in 48K)

edited May 2014 in Development
I don't recall any 8x2 multicolor routine for 30 columns that would work on all Spectrum models (including the Spectrum 48K), so I decided to write it myself:
LD SP,nn                    ; reference columns 5 and 6
LD HL,nn
LD DE,nn
LD BC,nn
EXX
LD HL,nn
LD DE,nn
LD BC,nn
LD IX,nn
LD IY,nn
LD (nn),IX                  ; columns 1 and 2
PUSH IY                     ; columns 5 and 6
PUSH BC                     ; columns 3 and 4
LD SP,nn                    ; reference columns 19 and 20
LD IX,nn
PUSH DE                     ; columns 19 and 20
LD DE,nn
LD BC,nn
PUSH IX                     ; columns 17 and 18
PUSH BC                     ; columns 15 and 16
PUSH DE                     ; columns 13 and 14
PUSH HL                     ; columns 11 and 12
EXX
PUSH BC                     ; columns 9 and 10
PUSH DE                     ; columns 7 and 8
LD SP,nn                    ; reference columns 27 and 28
PUSH HL                     ; columns 27 and 28
LD HL,nn
LD DE,nn
LD BC,nn
PUSH BC                     ; columns 25 and 26
PUSH DE                     ; columns 23 and 24
PUSH HL                     ; columns 21 and 22
LD HL,nn
LD (nn),HL                  ; columns 29 and 30
ADD HL,HL                   ; extra delay
XOR A                       ; extra delay

Executing it in a Spectrum 48K will take 16239T-15791T = 448T = 2 * 224T, as detailed below:
; 15791T
LD SP,nn                    ; reference columns 5 and 6
              ; 15801T
LD HL,nn
              ; 15811T
LD DE,nn
              ; 15821T
LD BC,nn
              ; 15831T
EXX
              ; 15835T
LD HL,nn
              ; 15845T
LD DE,nn
              ; 15855T
LD BC,nn
              ; 15865T
LD IX,nn
              ; 15879T
LD IY,nn
              ; 15893T
LD (nn),IX                  ; columns 1 and 2
              ; 15920T
PUSH IY                     ; columns 5 and 6
              ; 15944T
PUSH BC                     ; columns 3 and 4
              ; 15960T
LD SP,nn                    ; reference columns 19 and 20
              ; 15970T
LD IX,nn
              ; 15984T
PUSH DE                     ; columns 19 and 20
              ; 16000T
LD DE,nn
              ; 16010T
LD BC,nn
              ; 16020T
PUSH IX                     ; columns 17 and 18
              ; 16035T
PUSH BC                     ; columns 15 and 16
              ; 16046T
PUSH DE                     ; columns 13 and 14
              ; 16057T
PUSH HL                     ; columns 11 and 12
              ; 16068T
EXX
              ; 16072T
PUSH BC                     ; columns 9 and 10
              ; 16083T
PUSH DE                     ; columns 7 and 8
              ; 16094T
LD SP,nn                    ; reference columns 27 and 28
              ; 16104T
PUSH HL                     ; columns 27 and 28
              ; 16115T
LD HL,nn
              ; 16125T
LD DE,nn
              ; 16135T
LD BC,nn
              ; 16145T
PUSH BC                     ; columns 25 and 26
              ; 16160T
PUSH DE                     ; columns 23 and 24
              ; 16176T
PUSH HL                     ; columns 21 and 22
              ; 16192T
LD HL,nn
              ; 16202T
LD (nn),HL                  ; columns 29 and 30
              ; 16224T
ADD HL,HL                   ; extra delay
              ; 16235T
XOR A                       ; extra delay
              ; 16239T

Executing it in a Spectrum 128K/+2 will take 16297T-15841T = 456T = 2 * 228T, as detailed below:
; 15841T
LD SP,nn                    ; reference columns 5 and 6
              ; 15851T
LD HL,nn
              ; 15861T
LD DE,nn
              ; 15871T
LD BC,nn
              ; 15881T
EXX
              ; 15885T
LD HL,nn
              ; 15895T
LD DE,nn
              ; 15905T
LD BC,nn
              ; 15915T
LD IX,nn
              ; 15929T
LD IY,nn
              ; 15943T
LD (nn),IX                  ; columns 1 and 2
              ; 15974T
PUSH IY                     ; columns 5 and 6
              ; 15998T
PUSH BC                     ; columns 3 and 4
              ; 16014T
LD SP,nn                    ; reference columns 19 and 20
              ; 16024T
LD IX,nn
              ; 16038T
PUSH DE                     ; columns 19 and 20
              ; 16054T
LD DE,nn
              ; 16064T
LD BC,nn
              ; 16074T
PUSH IX                     ; columns 17 and 18
              ; 16089T
PUSH BC                     ; columns 15 and 16
              ; 16100T
PUSH DE                     ; columns 13 and 14
              ; 16111T
PUSH HL                     ; columns 11 and 12
              ; 16122T
EXX
              ; 16126T
PUSH BC                     ; columns 9 and 10
              ; 16137T
PUSH DE                     ; columns 7 and 8
              ; 16148T
LD SP,nn                    ; reference columns 27 and 28
              ; 16158T
PUSH HL                     ; columns 27 and 28
              ; 16169T
LD HL,nn
              ; 16179T
LD DE,nn
              ; 16189T
LD BC,nn
              ; 16199T
PUSH BC                     ; columns 25 and 26
              ; 16218T
PUSH DE                     ; columns 23 and 24
              ; 16234T
PUSH HL                     ; columns 21 and 22
              ; 16250T
LD HL,nn
              ; 16260T
LD (nn),HL                  ; columns 29 and 30
              ; 16282T
ADD HL,HL                   ; extra delay
              ; 16293T
XOR A                       ; extra delay
              ; 16297T

Executing it in a Spectrum +2A/+3 will take 16300T-15844T = 456T = 2 * 228T, as detailed below:
; 15850T
LD SP,nn                    ; reference columns 5 and 6
              ; 15860T
LD HL,nn
              ; 15870T
LD DE,nn
              ; 15880T
LD BC,nn
              ; 15890T
EXX
              ; 15894T
LD HL,nn
              ; 15904T
LD DE,nn
              ; 15914T
LD BC,nn
              ; 15924T
LD IX,nn
              ; 15938T
LD IY,nn
              ; 15952T
LD (nn),IX                  ; columns 1 and 2
              ; 15977T
PUSH IY                     ; columns 5 and 6
              ; 16001T
PUSH BC                     ; columns 3 and 4
              ; 16017T
LD SP,nn                    ; reference columns 19 and 20
              ; 16027T
LD IX,nn
              ; 16041T
PUSH DE                     ; columns 19 and 20
              ; 16057T
LD DE,nn
              ; 16067T
LD BC,nn
              ; 16077T
PUSH IX                     ; columns 17 and 18
              ; 16092T
PUSH BC                     ; columns 15 and 16
              ; 16103T
PUSH DE                     ; columns 13 and 14
              ; 16114T
PUSH HL                     ; columns 11 and 12
              ; 16125T
EXX
              ; 16129T
PUSH BC                     ; columns 9 and 10
              ; 16140T
PUSH DE                     ; columns 7 and 8
              ; 16151T
LD SP,nn                    ; reference columns 27 and 28
              ; 16161T
PUSH HL                     ; columns 27 and 28
              ; 16172T
LD HL,nn
              ; 16182T
LD DE,nn
              ; 16192T
LD BC,nn
              ; 16202T
PUSH BC                     ; columns 25 and 26
              ; 16221T
PUSH DE                     ; columns 23 and 24
              ; 16237T
PUSH HL                     ; columns 21 and 22
              ; 16253T
LD HL,nn
              ; 16263T
LD (nn),HL                  ; columns 29 and 30
              ; 16285T
ADD HL,HL                   ; extra delay
              ; 16296T
XOR A                       ; extra delay
              ; 16300T

I hope someone will find this useful!
Post edited by Einar Saukas on
Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
«1

Comments

  • edited August 2013
    Given the amount of data you'd need to shift I'm wondering if it could be used to provide a 60x96 wide pixel mode with 8 (per-pixel) colours. Also have a feeling JoeFish did it already, but I don't think there's been a public demo.
  • edited August 2013
    aowen wrote: »
    Given the amount of data you'd need to shift I'm wondering if it could be used to provide a 60x96 wide pixel mode with 8 (per-pixel) colours.

    Do you mean one color for each 4x2 pixel area? If so, the answer is yes.
    aowen wrote: »
    Also have a feeling JoeFish did it already, but I don't think there's been a public demo.

    AFAIK joefish implemented something different: 28 columns reading from a linear buffer. And I doubt it's possible to have more than 28 columns this way.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited August 2013
    I uploaded a demo here. It works on all Spectrum models!
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited August 2013
    Do you mean one color for each 4x2 pixel area? If so, the answer is yes.

    Yes. I was thinking that having a fixed bitmap and just updating the attributes might free up a few CPU cycles.
  • edited August 2013
    That's what my scrolling stuff does. The River Raid Demo is mostly a 4x-fat-pixel colour screen, though the multi-colour section there was only 14 characters wide to allow me time to use (a) a circular buffer and (b) synchronised border changes for the overscan roads. Doubling it up to 4x2x-fat-pixels would give you a wider screen.

    The main sprite is re-drawn each frame by copying the pixels and masking the attributes. But it's designed with the background pattern 00001111 in all its empty spaces, and parts of the sprite are inverted so that either the INK or the PAPER is transparent, depending whether more of the right or left half of the background would be visible around the sprite. This is to minimise colour clash.

    The boats and bridge are just drawn in the background fat pixels.

    I have experimented with using different 8x2 textures in the background and manipulating the attributes to draw simple patterns, and make them appear to scroll. It works OK for a few simple background shapes (e.g. boxes or bricks) but for game characters you'd want to use proper pixel sprites.
    Joefish
    - IONIAN-GAMES.com -
  • edited August 2013
    I uploaded a demo here. It works on all Spectrum models!

    all above 16k you mean to say ;)

    what would be the max interlace on a (original) 16k?

    PS, the color contrast in you demo is dizzeling.
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited August 2013
    Crisis wrote: »
    all above 16k you mean to say ;)

    what would be the max interlace on a (original) 16k?

    Given that all the 16K's RAM is contended and that multi-color is RAM intensive it's really a non-starter on the 16K. I suppose you could create an IF2 cart that would display a static image across 30 columns with 8x2 attributes or 20 columns with 8x1 attributes. A bit pointless though.
  • edited August 2013
    aowen wrote: »
    Given that all the 16K's RAM is contended and that multi-color is RAM intensive it's really a non-starter on the 16K. I suppose you could create an IF2 cart that would display a static image across 30 columns with 8x2 attributes or 20 columns with 8x1 attributes. A bit pointless though.

    Actualy my question is : "what would be the max for 16k contended screen"
    maybe 10 intead of 30 coloms wide?
    the "pixel-wide" will be bigger since the contention forces steps of 16 Tstate, afaik
    Maybe a simple MLT is easier?
    But this tread is about 30 colomns...:roll:

    ps an IF2 with an eprom ??
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited August 2013
    Crisis wrote: »
    all above 16k you mean to say ;)

    what would be the max interlace on a (original) 16k?

    PS, the color contrast in you demo is dizzeling.

    Yes, can work on ZX16, but DIVIDE interface must be connect and multicolor routine must be in DIVIDE ram in low 16kB of adress space.
  • edited August 2013
    velesoft wrote: »
    Yes, can work on ZX16, but DIVIDE interface must be connect and multicolor routine must be in DIVIDE ram in low 16kB of adress space.


    what if we start with just 1 tile off ZXodus/Bifrost ?
    it makes it small enough to start with.
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited August 2013
    Crisis wrote: »
    PS, the color contrast in you demo is dizzeling.

    Agreed, but I needed a graphics pattern with enough regularity to easily notice distortions, but enough variety to discard accidental matches.

    To those who don't feel like running the demo themselves, here's the result:

    155hqav.jpg
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited August 2013
    I don't recall any 8x2 multicolor routine for 30 columns that would work on all Spectrum models (including the Spectrum 48K), so I decided to write it myself


    Most interesting.
    Would interrupts work while displaying it? I mean AY music while this multicolour would be on the screen?
    ZX81/ZX Spectrum/Amiga/Atari music: http://yerzmyey.i-demo.pl/
  • edited August 2013
    Yerzmyey wrote: »
    Most interesting.
    Would interrupts work while displaying it? I mean AY music while this multicolour would be on the screen?

    You can use the same interrupt to both display multicolor and play AY. This is exactly what we did in Knights & Demons DX.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited August 2013
    Crisis wrote: »
    Actualy my question is : "what would be the max for 16k contended screen"
    maybe 10 intead of 30 coloms wide?
    the "pixel-wide" will be bigger since the contention forces steps of 16 Tstate, afaik
    Maybe a simple MLT is easier?
    But this tread is about 30 colomns...:roll:
    Try compiling the ZXodus code to run in contended RAM and you'll see the problem.
    ps an IF2 with an eprom ??
    A custom ROM cart, yes.
  • edited August 2013
    aowen wrote: »
    Try compiling the ZXodus code to run in contended RAM and you'll see the problem.


    A custom ROM cart, yes.

    You seem to work with 3 blocks like in
    t00:
         ld        hl, tile_map        ; point to tile map
        call    get_tile_pos
        ld        de, $4021            ; screen bitmap address
        call    output_bmp
        ld        de, $4041             ; next cell down
        call    output_bmp
        ld        de, x00
        call    output_atr
    
         ld        hl, tile_map + 1    ; point to tile map
        call    get_tile_pos
        ld        de, $4023            ; screen bitmap address
        call    output_bmp
        ld        de, $4043             ; next cell down
        call    output_bmp
        ld        de, x02
        call    output_atr
    
         ld        hl, tile_map + 2    ; point to tile map
        call    get_tile_pos
        ld        de, $4025            ; screen bitmap address
        call    output_bmp
        ld        de, $4045             ; next cell down
        call    output_bmp
        ld        de, x04
        call    output_atr
    
        ld        de, t01            ; modify jump address
        ld        hl, set_jump + 1
        ld        (hl), e
        inc        hl
        ld        (hl), d
        ret
    

    if i want to slim-down zxodus, should i choose a 3x3 grid, having 9 tiles?
    For contented memory its better to calculate the M-cycle then Tstate I supose.
    If every opcode is considered 16tstate or longer then the longer ones will give problems and should be avoided. but probably thats to simple, as useual ...:lol:
    probably a lot off extra NOP will be needed to time the correct write cyclus
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited August 2013
    Initial timing is probably the biggest problem. Am I right in thinking that you can't use IM2 on a 16K - you have to rely on a HALT instruction waiting for an IM1 interrupt to occur, which means the Speccy ROM routine kicks in first, which means you get variable timings if someone is touching the keyboard..?

    As for playing AY music and other things, you can simply do them after the critical colour timing has been done, when timing no longer matters.
    Joefish
    - IONIAN-GAMES.com -
  • edited August 2013
    joefish wrote: »
    Initial timing is probably the biggest problem. Am I right in thinking that you can't use IM2 on a 16K - you have to rely on a HALT instruction waiting for an IM1 interrupt to occur, which means the Speccy ROM routine kicks in first, which means you get variable timings if someone is touching the keyboard..?

    As for playing AY music and other things, you can simply do them after the critical colour timing has been done, when timing no longer matters.

    Might be a good occasion to use the IN A,(255) thing then? As it's 16k specific there's no need to worry about the later models freezing, and the IM1 can vary as much as it likes.
  • edited August 2013
    Good idea - I've never used the floating bus myself. There'd still be a fair bit of variability in the results of that as a test, but using that and say, the first 8 lines of contention you should easily have everything lined up exactly.
    Joefish
    - IONIAN-GAMES.com -
  • edited August 2013
    joefish wrote: »
    Initial timing is probably the biggest problem. Am I right in thinking that you can't use IM2 on a 16K - you have to rely on a HALT instruction waiting for an IM1 interrupt to occur, which means the Speccy ROM routine kicks in first, which means you get variable timings if someone is touching the keyboard..?

    As for playing AY music and other things, you can simply do them after the critical colour timing has been done, when timing no longer matters.


    the simplest thing that should be possible is having that IM2 in 16k.
    you will have to waste a mere 257 bytes on the table but once set correct the IM2 should work.
    the printer buffer is $5B00 giving $5B00 > including $5C00 =257 bytes as possible table and 5C5C as first available jumpadress. with 5c-2=5a (90) bytes free to create the first init. $7fff-5c5d= $23a2 = 9122 bytes free for heavily contended code ...
    why should it Not work ?
    http://www.worldofspectrum.org/infoseekid.cgi?id=0013431
    a 16 k IM2 clock
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited August 2013
    Crisis wrote: »
    the simplest thing that should be possible is having that IM2 in 16k.
    you will have to waste a mere 257 bytes on the table but once set correct the IM2 should work.
    I wouldn't bother wasting the bytes. Just don't plug in any dodgy interfaces. You can have the I regıster pointing to contended RAM but as a consequence you'll get ULA snow. My two concerns are a) you won't have enough RAM to have a decent sized viewport, and b) because of contention instead of 8x1 you'll get 16x1 at best (although I haven't tested this).
  • edited August 2013
    aowen wrote: »
    b) because of contention instead of 8x1 you'll get 16x1 at best (although I haven't tested this).

    With contention affecting every instruction, 16x1 wouldn't help too much.

    Multicolor 8x1 in only 8 or 10 columns is more likely.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited August 2013
    aowen wrote: »
    I wouldn't bother wasting the bytes. Just don't plug in any dodgy interfaces. You can have the I regıster pointing to contended RAM but as a consequence you'll get ULA snow. My two concerns are a) you won't have enough RAM to have a decent sized viewport, and b) because of contention instead of 8x1 you'll get 16x1 at best (although I haven't tested this).


    I like the part where the discussion turns into "then ... what is possible"

    a dutch way off saying is : "wie het kleine niet eert is het grote niet weert"
    meaning, if you dont mind about the small things you cant understand the value off the big things

    A few bright stripes would be nice to start with, perhaps a simple
    Begin: Noughts and Crosses ??

    And is there any way we can USE the snow effect?
    only if you can predict it i supose.
    Or make a Polar scene ???
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited August 2013
    I got 12 columns running multicolor 8x1 from contended memory:
    ; 15905T
    LD SP,nn                    ; reference columns 11 and 12
                  ; 15928T
    LD HL,nn
                  ; 15952T
    PUSH HL                     ; columns 11 and 12
                  ; 15976T
    LD HL,nn
                  ; 16000T
    PUSH HL                     ; columns 9 and 10
                  ; 16024T
    LD HL,nn
                  ; 16039T
    PUSH HL                     ; columns 7 and 8
                  ; 16050T
    LD HL,nn
                  ; 16060T
    PUSH HL                     ; columns 5 and 6
                  ; 16071T
    LD HL,nn
                  ; 16081T
    PUSH HL                     ; columns 3 and 4
                  ; 16092T
    LD HL,nn
                  ; 16102T
    PUSH HL                     ; columns 1 and 2
                  ; 16113T
    NOP  
                  ; 16117T
    NOP
                  ; 16121T
    NOP
                  ; 16125T
    NOP
                  ; 16129T
    

    I also tried other combinations of instructions but it didn't really help, although I didn't try too hard...
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited August 2013
    I got 12 columns running multicolor 8x1 from contended memory

    Ok, so is there enough RAM for the unrolled loop to do 6x6 tiles?
  • edited August 2013
    aowen wrote: »
    Ok, so is there enough RAM for the unrolled loop to do 6x6 tiles?

    Yes. The routine uses 224T (finishing exactly on time for the next raster scan line) and 31 bytes. Rendering a 6x6 tiles area would take 6*2*8*31=2976 bytes.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited August 2013
    Yes. The routine uses 224T (finishing exactly on time for the next raster scan line) and 31 bytes. Rendering a 6x6 tiles area would take 6*2*8*31=2976 bytes.

    I guess 6K is enough for a game engine. You'd want to LOAD the in-game screen directly though.
  • edited August 2013
    WOW

    I knew it!
    and you did it!!!

    I am curious how snowy it will be.
    AND as a bonus, with this throuly geniuos developpement now a larger 48 K picture is possible aswell !! ( i hope, is all about timing of course)

    HURAY!

    and congratulations!!


    ps if my brother would have known this, he never would have upgraded, back in 1984
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited May 2014
    It seems like 32-column 8x2 multicolor is also possible on a 48K.

    ;-99
    ld ix
    ld iy
    ld bc:ld de:ld hl
    exx
    ld bc:ld de:ld hl
    ;-5
    (0-1,2-3 shown) ld (..),hl ;+8,16 (put 0,1)
    (8-9,10-11 shown) ld hl:ld (..),hl ;+40,48 (put 2,3)
    (16-17,18-19 shown) ld hl:ld (..),hl ;+72,80 (put 4,5)
    (24-25,26-27 shown) ld hl:ld (..),hl ;+104,112 (put 6,7)
    ld hl ;122
    push iy ;137 (put 23,22)
    push hl ;148 (put 21,20)
    push de ;159 (put 19,18 )
    push bc ;170 (put 17,16)
    exx ;174
    push ix ;189 (put 15,14)
    push hl ;200 (put 13,12)
    push de ;211 (put 11,10)
    push bc ;222 (put 9,8 )
    ld sp ;232
    ld bc:ld de:ld hl ;262
    (10-11,12-13 shown) push hl ;+272,280 (put 29,28 )
    (14-15,16-17 shown) push de ;+288,296 (put 27,26)
    (18-19,20-21 shown) push bc ;+304,312 (put 25,24)
    (26-27,28-29 shown) ld hl:ld (..),hl ;+336,344 (put 30,31)
    ;-104

    Note that sp holds for the next line.

    Numbers are T-states starting from +0 (the last uncontended write before ULA access of the line). These numbers are written for contention scheme 7,6,5,4,3,2,1,0 but the code will work for 6,5,4,3,2,1,0,0 too.
  • edited May 2014
    It seems like 32-column 8x2 multicolor is also possible on a 48K.

    This is awesome!

    Did you validate it already? Otherwise I will try to validate it myself later tonight.
    Creator of ZXDB, BIFROST/NIRVANA, ZX7/RCS, etc. I don't frequent this forum anymore, please look for me elsewhere.
  • edited May 2014
    I haven't tried this yet. I never coded multicolors for contended memory before :)
Sign In or Register to comment.