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
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.
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.
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.
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
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...
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.
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.
Comments
Right now, my check routine is this,
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.
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.
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.
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.
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...
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.
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.