My main thoughts on this are to give the code a "virtual run" in the following manner:
Start at the beginning (0x0200), and mark the instructions as code as I go. I only have to actually respond to GOTO, GOSUB, and SKIPIF.
Responding to a GOTO is simple... just jump the program counter.
Responding to a GOSUB is reasonably simple... simply go to the location and progress until I reach a RETURN.
The slight problem with SKIPIF is that the next instruction might be a GOTO, so I have to be sure to try the next instruction as well as the instruction after that.
So, just thinking and typing here, let's take a look at pong:
0210 GOSUB 2D4
021C SKIPIF V0==00
021E GOTO 21A
0232 SKIPIF KEYUP(V0)
0238 SKIPIF KEYUP(V0)
0244 SKIPIF KEYUP(V0)
024A SKIPIF KEYUP(V0)
0264 SKIPIF V6!=02
0266 GOTO 278
0268 SKIPIF V6!=3F
026A GOTO 282
026C SKIPIF V7!=1F
0270 SKIPIF V7!=00
0276 GOTO 22A
0280 GOTO 28A
028A SKIPIF VF==01
028C GOTO 2A2
0292 SKIPIF VF==01
0294 GOTO 2BA
0298 SKIPIF VF==01
029A GOTO 2C8
029E SKIPIF VF==01
02A0 GOTO 2C2
02A6 GOSUB 2D4
02AA GOSUB 2D4
02AE SKIPIF V3==01
02B4 SKIPIF V3==01
02B8 GOTO 216
02BC SKIPIF V9!=FE
02C0 GOTO 2C8
02C4 SKIPIF V9!=02
02CE SKIPIF V6!=40
02D2 GOTO 26C
02D6 BCD VE
02D8 LOAD V0,V2
02F2 DATA 0000
02F4 DATA 0000
Starting at 0200, we get all the way up to 210 before having to do anything with GOSUB 2D4. I'm just going to add 2D4 to the GOSUB list and continue on...
At 021C, I reach a SKIPIF, so I'll add 0220 to the SKIPIF list.
And a good thing, too, as 021E contains a GOTO, which returns us to 021A, which is already marked as code, so we'll stop and find something else to look at.
Thus far, 0200 through 021F are marked as code.
So, I'll grab the one value I have in the GOSUB list... 02D4, and I'll progress from there.
I'll mark the code all the way up to 02E8, which is a RETURN, at which point I'll stop again.
Now, 0200..021F and 02D4..02E9 are marked as code.
Which leaves only my SKIPIF at 0220.
I'll be blowing right through the next few SKIPIFs, as they don't have GOTOs after them, until 0266, so add 0268 to the SKIPIF list, and proceed to 0278.
At this point, 0200..0267 and 02D4..02E9 are marked as code.
And so on, until I have marked all of the code, and come to realize that 02EA..02F5 are the only data.
And this is all well and good, and relatively easy to do in my disassembler.
There is one opcode that I am concerned with...
Add V0 to a number, and jump the program counter there.
A nifty opcode, to be sure. Essentially the "ON A GOTO X,Y,Z" of CHIP8.
Kind of throws a monkeywrench into the works of the disassembler. I have to assume that any value of V0 (0..255) MIGHT be valid for this particular GOTO.
Anyway, should be fun, right?