That’s what the “hardware collision” bit is about. You place sprite 0 at a certain location on screen, and you can find out when that sprite gets drawn (with some certain other restrictions / assumptions). IIRC, the collision bit gets set when a pixel from the sprite is drawn overlapping a background pixel. This is how early games like Super Mario Bros. drew the status bar, but Super Mario Bros. could just spin the CPU waiting for this.
There are two other mechanism I know off the top of my head.
One is to put some circuitry on the cartridge, and then arrange the usage of tiles such that all the background tiles are in one bank and all the foreground tiles are in another. If you do this right, you get an address line which cycles high and low once each scanline–and you can put a circuit on the cartridge which counts the scanlines, triggering an interrupt. This was only available if you could put that circuitry (usually, a “mapper”) on the cartridge.
The last method is to count cycles.
I would note that among other differences, this is much, much easier on a Game Boy. The Game Boy has a register you can read which tells you which row you are on. Not the only thing that’s easier on a Game Boy—there’s also a hblank interrupt, and the tilemap is larger than the screen. Anyone interested in NES programming but unsure about how much they like dealing with obscure technical problems may want to try Game Boy programming first to get a taste for it.
Yes: but it's messy. You spin in a loop with a BIT instruction polling the PPU_STATUS register and a BVC instruction pointing backwards waiting for bit 6 to be set. Besides the fact that you're stuck doing this, the main problem is synchronization, this little loop takes 7 CPU cycles (with each CPU cycle taking 3 PPU cycles, or 3 "pixels" of distance) leading to an 21 "pixel" variance. When dealing with the very short horizontal blanking period between scanlines, it leaves very little time to do anything meaningful with the PPU in that window.
If you've ever noticed some "weird flickering" near status bars in NES games, this is probably the culprit: Few very skilled developers were able to pull it off cleanly.
The TV syncs to the clock in the input signal that the console generates. The console knows what line the TV was on because it's the line that the console is currently outputting. Analog TVs were very simple devices where the signal coming in via the wire or antenna was basically pumped directly to the CRT to manipulate the beam. While at the user's end it looked like a raster, it's all analog tricks.
Imagine a text file pushed out theough a serial port, all the data is just dumped on to the wire and the other end worries about interpreting carriage returns and line feeds. You just imagined how old line printers worked!
When the TV wasn't able to figure out the sync signal you'd get rolling [1] or tearing [2] where the picture was being displayed the best the TV could make out.
There are two other mechanism I know off the top of my head.
One is to put some circuitry on the cartridge, and then arrange the usage of tiles such that all the background tiles are in one bank and all the foreground tiles are in another. If you do this right, you get an address line which cycles high and low once each scanline–and you can put a circuit on the cartridge which counts the scanlines, triggering an interrupt. This was only available if you could put that circuitry (usually, a “mapper”) on the cartridge.
The last method is to count cycles.
I would note that among other differences, this is much, much easier on a Game Boy. The Game Boy has a register you can read which tells you which row you are on. Not the only thing that’s easier on a Game Boy—there’s also a hblank interrupt, and the tilemap is larger than the screen. Anyone interested in NES programming but unsure about how much they like dealing with obscure technical problems may want to try Game Boy programming first to get a taste for it.