Jump to content
IGNORED

HOWTO: Identify Patterns on Screen


Recommended Posts

In order to contribute and help budding Coleco/ADAM programmers I intend to share various code snippets that will help you along.

I have found over the years that specific details are hard to come by so I will help where I can but I am not going to teach you Z80 assembly language.  It is not as hard as you think and can look intimidating at times but don't give up.

 

If you use assembly language you will gain speed and space over any higher level language.  (my opinion you may feel different)

 

That said.

Have you ever wanted to know what pattern your sprite is over or just wanted to know what pattern (or color) is at what position on the screen.

 

Maybe you want to build a wall that you do not want to pass through so your wall is pattern 45.

Well, you can say if a = 45 then do not pass.

 

In assembly that looks like this

LD A, ???? (magic number)

CP 45       ; (Compare) or if A = 45

JP Z DO_NOT_PASS    ; If yes then jump to Do not pass routine if no then continue on.

 

; Continue Journey

code....

RET                             ;(Return from where you called from)

 

DO_NOT_PASS:          ; Do not continue moving through pattern.

RET                             ;(Return from where you called from)

 

But how do you get that important magic 45 or other value into A

 

Well, in another post I will show you how to set up graphics but for now we will just say it is there.

 

For now it is sitting in GRAM, VRAM....The Ram connected to the TI9928 Graphics Chip.
The way Colecovision works is that the Z80 uses Ram and the Graphic Chip uses Ram so in order to get to the 16k Graphics Ram you have to go through a port which kind of sucks because it creates a bottle neck.  However the Z80 is mighty fast so we can get away with a few things and scrolling is not one of them.  That does not mean you can't have scrolling games, it just means they won't look as smooth as modern systems.

 

Because Coleco Sprite Y and X values range from 0 to 192 Y and 0 to 256 X we have to divide them by 8 to get the proper Rows and Columns

 

In the Coleco world we have 32x24 screen patterns (768)

 

Mathematically it all adds up and divides equally as you would expect in the computer world.

 

The routine is actually 4 parts.

1st is to divide by 8 and get the Rows

2nd is to divide by 8 and get the Columns

3rd is to send (OUT) to PORT 0BFh.

4th is put that returned value (IN) 0BEh into A

 

Port BE VRAM Data (Read/Write)

Port BF VDP Status Registers (Read Only)

 

I do not want to get into the AND's and PORTS right now because that is information overload and a distraction so for now I am sticking with minimum code.

 

Copy and paste or use the asm attachment.

 

; Tile Identify Routine (c) 2020 "From Scratch" Enterprises
; Free to use but please use love for me in the credits.

 

; To find Pattern under Sprite. (upper left hand corner)
; Sprite Definition (Y, X, Pattern, Color)
; LD Y into (OFFSET_Y) and LD X into (OFFSET_X) then call SPRITE_TO_TILE
; Pattern value will come back in A

; To find the pattern on screen (no sprite) LD HL with tile position 0-767 + VRAM_NAME ($1800)
; To find the pattern color (no sprite) LD HL with tile position 0-767 + VRAM_COLOR ($2000)
; Call QUICK_TILE.  Pattern value will return in A

 

VRAM_NAME:  EQU $1800
 

SPRITE_TO_TILE:
    LD HL, VRAM_NAME
    LD A, (OFFSET_Y)   ; offset Y (ROW)
    CP 0                       ; can't divide by zero skip to find Columns
    JP Z, FIND_COLUMN
    SRL A                     ; divide by 8 (192/8) 24 Rows (actually divide 3 times by 2)
    SRL A
    SRL A
    LD B, A
    LD DE, 32
    XOR A
ZERO:
    ADC HL, DE
    DJNZ ZERO
FIND_COLUMN:
    LD A, (OFFSET_X)   ; offset X (Column)
    CP 0                       ; can't divide by zero skip to QUICK_TILE which calls port to get value
    JP Z, QUICK_TILE
    SRL A                     ; divide by 8 (256/8) 32 Columns (actually divide 3 times by 2)
    SRL A
    SRL A
    LD E, A
    LD D, 0
    XOR A
    ADC HL, DE

QUICK_TILE:
    DI
    LD A, L
    OUT (0BFh), A      ; (OUT) Lower Bits
    LD A, H
    AND 3Fh
    OUT (0BFh), A      ; (OUT) Higher Bits
    EI

    IN A, (0BEh)         ; (IN) Return value into A
    RET

 

If you find errors or inconsistencies please let me know in the comments.

 

 

 

 

 

 

 

 

 

 

Identify Tile.asm

Edited by Itchy Scratchy
clean up code a bit
  • Like 2
Link to comment
Share on other sites

Feel free to comment on how this routine could be better.

 

I highly recommend that in your programing journey to start commenting your code.

I am finding that going back to older work is like what the **** did I do here and why does it work.

If you find yourself in a full 32k project with over 4000 lines of code then you will wish you commented at least the important stuff.


Even in my previous post I have updated, refined, edited you name it at least 20 times to simplify it for you.

Edited by Itchy Scratchy
Link to comment
Share on other sites

19 hours ago, Tony Cruise said:

Very well explained.

Thank you.

I am sure I missed some important parts but how many times can you go back and edit something.
Next time I will write the whole thing out then copy and paste instead of winging most of it from memory.

 

Then again I may end up giving a basic Z80 Assembly language course after all.
It seems that all the books on the market are geared toward engineering students.

 

Edited by Itchy Scratchy
Link to comment
Share on other sites

Just a couple of things, if I may..

 

I think there's a potential bug lurking right here:

 

    SRL A                     ; divide by 8 (192/8) 24 Rows (actually divide 3 times by 2)
    SRL A
    SRL A
    LD B, A

    .. <enter loop with B>

 

When OFFSET_Y is in the range of (0..7) the result after dividing by 8 will be 0 and that will cause the loop to repeat 256 times. You should check for Z after the last SRL A and skip the loop if needed.

 

 

Anyway, I think the approach of dividing by 8 and then multiplying that same value by 32 is a bit cumbersome and unnecessary . Here's an easier alternative to calculate the pattern address for a given Y_OFFSET in A. I've put some comments laying out the bit fields to help visualize what's going on:

 

          //A=OFFSET_Y   // V7 V6 V5 V4 V3 V2 V1 V0
          AND  #F8      // V7 V6 V5 V4 V3 0  0  0
          LD   H,0
          LD   L,A
          ADD  HL,HL     // 0 0 0 0 0 0 0  V7 | V6 V5 V4 V3 0 0 0 0
          ADD  HL,HL     // 0 0 0 0 0 0 V7 V6 | V5 V4 V3 0  0 0 0 0
          LD   DE,VRAM_NAME
          ADD  HL,DE     // HL=VRAM_NAME+(Y*32)   

 

I'm taking advantage of the fact that we're multiplying an unknown value (OFFSET_Y) by a power of 2. Also that zeroing the lowest 3 bits of something is in fact the same as dividing by 8 and then multiplying the result again by 8, so we just need to multiply by 4 to get the proper offset (Y*32).

 

This way there's no need for expensive loops nor safety checks when B=0.

 

The OFFSET_X part is even easier. We know the lowest 5 bits of the adddress in HL are always 0, so we can just divide X by 8 and add the result to the L register:

 

          LD   A,(OFFSET_X)   // X7 X6 X5 X4 X3 X2 X1 X0
          SRL  A
          SRL  A
          SRL  A         // 0 0 0 X7 X6 X5 X4 X3
          OR   L
          LD   L,A       // V5 V4 V3 X7 X6 X5 X4 X3    

 

 

Regards

Jorge

 

 

Edited by Maltanto
Minor corrections
  • Like 1
Link to comment
Share on other sites

 

// IN: (OFFSET_Y, OFFSET_X)
// OUT: HL=VRAM_NAME ADDRESS, A=PATTERN    
        LD   A,(OFFSET_Y)
        AND  #F8      // V7 V6 V5 V4 V3 0  0  0
        LD   H,0
        LD   L,A
        ADD  HL,HL     // 0 0 0 0 0 0 0  V7 | V6 V5 V4 V3 0 0 0 0
        ADD  HL,HL     // 0 0 0 0 0 0 V7 V6 | V5 V4 V3 0  0 0 0 0
        LD   DE,VRAM_NAME
        ADD  HL,DE          // HL=VRAM_NAME+(Y*32)  

        LD   A,(OFFSET_X)   // X7 X6 X5 X4 X3 X2 X1 X0
        SRL  A
        SRL  A
        SRL  A         // 0 0 0 X7 X6 X5 X4 X3
        OR   L
        LD   L,A       // V5 V4 V3 X7 X6 X5 X4 X3

 

// READ VRAM

// THIS IS OK ON EMULATORS, BUT MOST CERTAINLY WON'T WORK ON THE REAL HARDWARE DUE TO TIMING CONSTRAINTS

        DI
        LD    A,L
        OUT   (#BF),A   
        LD    A,H
        AND   #3F
        OUT   (#BF),A 
        IN    A,(#BE)
        EI
        RET

 

 

Link to comment
Share on other sites

I want to try your formula to see if it does actualy work on the real deal.

I have physical hardware and a lot of eproms sitting around.

 

Which brings me to an important point.

The routine I have given the community I have used in many programs on both emulators for development and real hardware so it has been tested.

 

My goal for teaching and developing is not just to do it but to also have good coding practices.

 

I remember being really upset when I moved from Workbench 1.3 on my Amiga to 2.0 where as a ton of programs did not work because they were created at such a low level and directly used the hardware instead of going through the BIOS.  Low level is great for DEMOS, lousy for practical software.

 

Modular, functional and easy to read but at the same time if anyone can introduce better and more efficient code I will turn from teacher to student in a heartbeat, no pride or ego here.

Link to comment
Share on other sites

This brings me to an interesting point.

 

Where are all the Colecovision and ADAM Demos?

 

The Coleco formula is still going strong some 40 years later yet it is still a small community.

 

Youtube is full of TI99/4A fans creating stuff that would knock your socks off yet Coleco has little to nothing.

 

I want to just toy around a bit when Thrippin is completed..  I hope you join in.

 

Working hard on it in between life's activities.  That darn NMI is a harsh mistress.

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.
Note: Your post will require moderator approval before it will be visible.

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.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...