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,
'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 bufferBefore 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.
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 resDid 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 #checkScanlineIt 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.