Shop OBEX P1 Docs P2 Docs Learn Events
Understanding WAITVID - Page 3 — Parallax Forums

Understanding WAITVID

13»

Comments

  • Vega256Vega256 Posts: 197
    edited 2011-07-25 08:56
    potatohead wrote: »
    That has happened to me. Yeah, you are close!

    You have a sync problem. The way to solve it is to think through the states of both the TV driver and the renderer and have them do interlocking things to sync up. It could be you are really close, and not properly initializing your renderer. Have it keep track of it's own scan lines, and reset that every frame sync.

    For the frame: Have the TV driver write a one to a HUB variable at some specific time. I recommend after the last scan line has completed. Have the renderer start up, render it's first scan line, then write a 0 to that same location, looping to check for the 1, before rendering all the scan lines. When they are done, initialize for the next frame, and repeat. The renderer can count it's own scan lines. That is all that you need to sync up for the frame.

    For the scan line, I don't know if you are using a single or double buffer. The single method has been discussed above, and it's tricky. Not recommended. Reads like you've got the scan line working though, so don't tinker with it yet.

    For a double buffer, I suggest having the TV COG read it's buffer address during the HBLANK, so that it's rendering from one of the two buffers on that scan line, directed by the render COG. After it fetches that buffer address, have it write a 0 to that location. The render cog writes the buffer address it just rendered to that same location, and it loops and waits for the zero to be written before advancing to render the next scan line.

    Those two latches will keep the render COG rendering in the right place, at the right time. The 80x50 driver in my blog uses that basic latch sync technique, if you want to look at some code.
    Yeah, it looks like I should try something different.

    Right now, my check routine is this,
                            'Wait for the TV driver to render the last scanline
    checkScanline           rdlong lineNum, nextLineAddr    'Get current line number
                            cmp lineNum, #223       wz      'Last scanline ?
                                                            'Max 223
                  if_nz     jmp #checkScanline              'No, check again
                                                            'Yes, start filling buffer
    
  • potatoheadpotatohead Posts: 10,261
    edited 2011-07-25 09:10
    I hate to write this, but....

    Before tearing into something that almost works, have you tried simply adding or subtracting a scan line from your check? If the tiles are moving a frame at a time, and all else is good, you are just off one scan line, or maybe two somewhere.

    Better to know where the problem is, but... there is making it work too. :)
  • Vega256Vega256 Posts: 197
    edited 2011-07-25 09:13
    potatohead wrote: »
    I hate to write this, but....

    Before tearing into something that almost works, have you tried simply adding or subtracting a scan line from your check? If the tiles are moving a frame at a time, and all else is good, you are just off one scan line, or maybe two somewhere.

    Better to know where the problem is, but... there is making it work too. :)
    That's what I thought. I did subtract and add one line before, but same thing happened. I even tried trimming a few scanlines off. No success.
  • ericballericball Posts: 774
    edited 2011-07-25 10:11
    Vega256 wrote: »
    That's what I thought. I did subtract and add one line before, but same thing happened. I even tried trimming a few scanlines off. No success.

    Walk through your code and make sure all of your pointers and counters (including any self-modifying instructions) are getting reset properly every frame. You should also do a "static data" test on your display cog. Set each line buffer to a set (but different) pattern and make sure it doesn't vary between frames (assuming that line 1 is always displays buffer 1). Also check the render cog and make sure it has the same assumption and resets & syncs each frame.
  • potatoheadpotatohead Posts: 10,261
    edited 2011-07-25 10:27
    Yep. If adjusting the scan line didn't work, Eric is right on.
  • Vega256Vega256 Posts: 197
    edited 2011-07-25 17:20
    Post 100. First star.

    potatohead wrote: »
    That has happened to me. Yeah, you are close!

    You have a sync problem. The way to solve it is to think through the states of both the TV driver and the renderer and have them do interlocking things to sync up. It could be you are really close, and not properly initializing your renderer. Have it keep track of it's own scan lines, and reset that every frame sync.

    For the frame: Have the TV driver write a one to a HUB variable at some specific time. I recommend after the last scan line has completed. Have the renderer start up, render it's first scan line, then write a 0 to that same location, looping to check for the 1, before rendering all the scan lines. When they are done, initialize for the next frame, and repeat. The renderer can count it's own scan lines. That is all that you need to sync up for the frame.

    For the scan line, I don't know if you are using a single or double buffer. The single method has been discussed above, and it's tricky. Not recommended. Reads like you've got the scan line working though, so don't tinker with it yet.

    For a double buffer, I suggest having the TV COG read it's buffer address during the HBLANK, so that it's rendering from one of the two buffers on that scan line, directed by the render COG. After it fetches that buffer address, have it write a 0 to that location. The render cog writes the buffer address it just rendered to that same location, and it loops and waits for the zero to be written before advancing to render the next scan line.

    Those two latches will keep the render COG rendering in the right place, at the right time. The 80x50 driver in my blog uses that basic latch sync technique, if you want to look at some code.

    I tried your method, but when I did, I didn't get tiles at all; I got stripes. Did I code this correctly as you described? I had to reverse the bits written to the register; the TV cog will write a zero and the tile cog will check for zero and write a one.
    con
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      paramcount = 2
    
      '80,000,000 = 1 second
      '80 = 1 microsecond
      '8 = 0.1 microsecond
    
      'Refesh Rate = 16666.666666667 microseconds
      
    var
    
      long nextLineAddress
      long scanlineBufferAddress
      long tableAddress
      long tileDefAddress
      
      long nextLine
      long scanlineBuffer [64]
      byte table [960]
    
    obj
    
      tv    :       "dk_tv_drv"
        
    pub main
    
      nextLineAddress := @nextLine
      scanlineBufferAddress := @scanlineBuffer
      tableAddress := @table
      tileDefAddress := @tile0
      
    
      'longfill (@scanlineBuffer, $02020202, 64)          'Clear scanline buffer to black
    
      bytefill (@table, 7, 960)
      table [0] := 0
      table [1] := 1
      table [2] := 2
      table [3] := 3
      table [4] := 4
      table [5] := 5
      table [6] := 6
    
      table [32] := 1
    
      waitcnt ((clkfreq * 2) + cnt)
    
      tv.start (@nextLineAddress)
      cognew (@start, @nextLineAddress)                                                                                                                 
    
    dat
    
    
    {
    white           $07
    lightGrey       $05
    grey            $04
    black           $02
    
    red             $5C
    orange          %6C
    yellow          %8C
    green           %AC
    blue            %0C
    purple          %2C
    magenta         %3C
    }
    
    
    tile0   long  $07070707, $07070707
            long  $07070707, $07070707
            long  $07070707, $07070707
            long  $07070707, $07070707
            long  $07070707, $07070707
            long  $07070707, $07070707
            long  $07070707, $07070707
            long  $07070707, $07070707
    
            long  $0c0c0c0c, $0c0c0c0c
            long  $0c0c0c0c, $0c0c0c0c
            long  $0c0c0c0c, $0c0c0c0c
            long  $0c0c0c0c, $0c0c0c0c
            long  $0c0c0c0c, $0c0c0c0c
            long  $0c0c0c0c, $0c0c0c0c
            long  $0c0c0c0c, $0c0c0c0c
            long  $0c0c0c0c, $0c0c0c0c
    
            long  $05050505, $05050505
            long  $05050505, $05050505
            long  $05050505, $05050505
            long  $05050505, $05050505
            long  $05050505, $05050505
            long  $05050505, $05050505
            long  $05050505, $05050505
            long  $05050505, $05050505
    
            long  $acacacac, $acacacac
            long  $acacacac, $acacacac
            long  $acacacac, $acacacac
            long  $acacacac, $acacacac
            long  $acacacac, $acacacac
            long  $acacacac, $acacacac
            long  $acacacac, $acacacac
            long  $acacacac, $acacacac
    
            long  $04040404, $04040404
            long  $04040404, $04040404
            long  $04040404, $04040404
            long  $04040404, $04040404
            long  $04040404, $04040404
            long  $04040404, $04040404
            long  $04040404, $04040404
            long  $04040404, $04040404
    
            long  $5c5c5c5c, $5c5c5c5c
            long  $5c5c5c5c, $5c5c5c5c
            long  $5c5c5c5c, $5c5c5c5c
            long  $5c5c5c5c, $5c5c5c5c
            long  $5c5c5c5c, $5c5c5c5c
            long  $5c5c5c5c, $5c5c5c5c
            long  $5c5c5c5c, $5c5c5c5c
            long  $5c5c5c5c, $5c5c5c5c
    
            long  $2c2c2c2c, $2c2c2c2c
            long  $2c2c2c2c, $2c2c2c2c
            long  $2c2c2c2c, $2c2c2c2c
            long  $2c2c2c2c, $2c2c2c2c
            long  $2c2c2c2c, $2c2c2c2c
            long  $2c2c2c2c, $2c2c2c2c
            long  $2c2c2c2c, $2c2c2c2c
            long  $2c2c2c2c, $2c2c2c2c
    
            long  $02020202, $02020202
            long  $02020202, $02020202
            long  $02020202, $02020202
            long  $02020202, $02020202
            long  $02020202, $02020202
            long  $02020202, $02020202
            long  $02020202, $02020202
            long  $02020202, $02020202        
    
    dat
    
    
    org 0
    
    
    
                            
    start                   'Load parameters
                            mov nextLineAddr, par
                            rdlong nextLineAddr, nextLineAddr
    
                            mov scanlineBufferAddr, par                            
                            add scanlineBufferAddr, #4
                            rdlong scanlineBufferAddr, scanlineBufferAddr
    
                            mov tableAddr, par
                            add tableAddr, #8
                            rdlong tableAddr, tableAddr
    
                            mov baseTileDefAddr, par
                            add baseTileDefAddr, #12
                            rdlong baseTileDefAddr, baseTileDefAddr
    
    
                            'Initialize data
                            mov numWaitvids, #32
                            mov tileRow, #0
                            mov tableIndex, #0
    
                            
    
    
    
    loadNextLine            mov tileOffsetA, tileRow
                            and tileOffsetA, #%111  wr
                            shl tileOffsetA, #3             'Multiply table entry by 8
                            add tileOffsetA, baseTileDefAddr
    
                            add tileRow, #1
    
                            mov counter, numWaitvids
                            mov scanlineIndex, scanlineBufferAddr
    
    loopA                   mov tileEntryAddr, tableAddr
                            add tileEntryAddr, tableIndex
    
                            rdbyte tileOffsetB, tileEntryAddr 'Read in an entry from the sprite table                                               
                            shl tileOffsetB, #6             'Multiply table entry by 64
                            add tileOffsetB, tileOffsetA    'Add to form an address
    
                            rdlong firstNibble, tileOffsetB 'Get pixel data
                            add tileOffsetB, #4
                            rdlong secondNibble, tileOffsetB
                            
                            add tableIndex, #1                                                                             
                            mov tmp, tileRow
    
                            wrlong firstNibble, scanlineIndex                       'Write first nibble data to scanline buffer
                            add scanlineIndex, #4                                   'Point to next buffer index
                            wrlong secondNibble, scanlineIndex                      'Write second nibble data to scanline buffer
                            add scanlineIndex, #4                                   'Point to next buffer index
    
                            djnz counter, #loopA            'Done with this line ?
                                                            'No, do next tile
                                                            'Yes, do next tile row
    
                            cmp tableIndex, #32     wz
                  if_z      call #checkScanline
    
    
    continue                mov tmp, tileRow
                            and tmp, #%111
                            cmp tmp, #0             wz, wc
                  if_nz     sub tableIndex, numWaitvids
    
                            cmp tableIndex, maxIndex wz
                  if_z      mov tableIndex, #0
                            jmp #loadNextLine
    
    
    checkScanline           wrlong value, nextLineAddr      'Write '1' to register
    checkScanline2          rdlong lineNum, nextLineAddr    'Wait for '0' on the register
                            cmp lineNum, #0         wz      'Last scanline ?
                  if_nz     jmp #checkScanline2             'No, check again
                                                            'Yes, start filling buffer
    checkScanline_ret       ret
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    maxIndex                long    960
    value                   long    1
    
    nextLineAddr            res
    scanlineBufferAddr      res
    tableAddr               res
    baseTileDefAddr         res
    
    lineNum                 res
    tileRow                 res
    
    tableIndex              res
    
    tileEntryAddr           res
    tileTableEntry          res
    tileAddr                res
    
    tileData                res
    scanlineIndex           res
    
    counter                 res
    numWaitvids             res
    
    tileOffsetA             res
    tileOffsetB             res
    
    firstNibble             res
    secondNibble            res
    
    tmp                     res
    
  • potatoheadpotatohead Posts: 10,261
    edited 2011-07-25 20:43
    Well, I would undo what you did, because you got tiles that way.

    Did you verify your render cog initializes correctly, and that it doesn't have a value creeping? And have you done a static data test?

    Looks like it should work on first glance. What is the TV COG doing, and when does it write it's zero?

    Are you planning to add sprites to this?

    If so, you should consider a double buffer, or return to the method CardboardGuru used. I've never examined that driver, so I don't know what that method is. Maybe that one was single buffered, but used a different timing scheme. Adding sprites to a single buffer, done the way discussed on this thread is difficult. Fine for a tile display, or bitmap, but not much else.
                            cmp tableIndex, #32     wz         
                 if_z      call #checkScanline
    
    It occurs to me that you might not be calling checkScanline. Rather than compare there, shouldn't checkScanline just happen after the scanline has been rendered? Should just fall through after the djnz, no compare needed? I'm a little confused by that bit of code, and "continue" below.

    Seems like that can all be positioned at the top of the loop...
  • Vega256Vega256 Posts: 197
    edited 2011-07-26 05:03
    potatohead wrote: »
    ...Are you planning to add sprites to this?

    If so, you should consider a double buffer, or return to the method CardboardGuru used. I've never examined that driver, so I don't know what that method is. Maybe that one was single buffered, but used a different timing scheme. Adding sprites to a single buffer, done the way discussed on this thread is difficult. Fine for a tile display, or bitmap, but not much else...

    Advice taken.

    I believe that my best route is to just use CardboardGuru's driver. It already has the capabilities am looking for, I just need to tweak it a bit.
  • potatoheadpotatohead Posts: 10,261
    edited 2011-07-26 07:39
    Don't blame you for using that other driver. I enjoyed trying to help you with this one. Maybe come back at some other point and continue. You got a fair ways down the road on this stuff. I've done the same too, balancing moving on other things, with sorting out a video related thing. Hope more good than harm was done. :)

    FWIW, I didn't mean your effort was bad. Got pinned on a earlier one using single buffers and sprite type functions. Was hoping to help you avoid the same result, that's all.
Sign In or Register to comment.