It's mostly covered by Sik, but I'll add a bit more detail on a few points. The H counter is simple enough, here are the notes on it from my Emulator:
Code: Select all
// The internal hcounter is 9-bit, and the external hcounter is 8-bit. The upper 8 bits
// of the 9-bit internal hcounter are used to build the 8-bit external hcounter, as
// shown below:
// Internal counter: 876543210
// External counter: 87654321
The V counter is actually quite a bit more complex. Here's its detail:
Code: Select all
// The internal vcounter is 9-bit, and the external vcounter is 8-bit. The way the
// internal counter is mapped to the external counter depends on the interlace mode.
// Given that the internal vcounter is 9-bit, the way the bits are mapped from the
// internal counter to the external counter is given below:
// Internal counter: 876543210
// External, no Interlacing: 76543210
// External, interlace normal: 76543218
// External, interlace double: 65432107
Regarding the reading of the HV counter, as Sik mentioned it does indeed get modified "live", meaning you can get what's called a "torn read" where only part of the data is updated. You don't get a case where the lower bits are effectively forced to "1" though, that's not what happens. What happens is that the 68000 "latches" each bit of the 16-bit value at
almost the same time, but not exactly. The end result is, that you usually get a good read. Rarely though (from memory, maybe 1 time out of 100), you get a case where some of the bits (and it's basically random which bits) are from the previous value, and some of the bits are from the new value. This can result in the counter appearing to jump either forwards or backwards, as well as a few impossible values occurring. If you're relying on good reads from the HV counter, you need to be aware of this possibility, and try and deal with it. How easy that is to do will depend on how often you read the counter and what you're trying to use it for.
To go a step further and make this more complex than it probably needs to be, you also need to know how the HV counter values map to the actual positions in the HV scan process over the screen. For that, here's the data tables:
Code: Select all
// Analog screen sections in relation to HCounter (H32 mode):
// -----------------------------------------------------------------
// | Screen section | HCounter |Pixel| Pixel |Serial|Serial |MCLK |
// | (PAL/NTSC H32) | value |clock| clock |clock |clock |ticks|
// | | |ticks|divider|ticks |divider| |
// |----------------|-----------|-----|-------|------|-------|-----|
// |Left border |0x00B-0x017| 13 |SCLK/2 | 26 |MCLK/5 | 130 |
// |----------------|-----------|-----|-------|------|-------|-----|
// |Active display |0x018-0x117| 256 |SCLK/2 | 512 |MCLK/5 |2560 |
// |----------------|-----------|-----|-------|------|-------|-----|
// |Right border |0x118-0x125| 14 |SCLK/2 | 28 |MCLK/5 | 140 |
// |----------------|-----------|-----|-------|------|-------|-----|
// |Front porch |0x126-0x127| 9 |SCLK/2 | 18 |MCLK/5 | 90 |
// |(Right Blanking)|0x1D2-0x1D8| | | | | |
// |----------------|-----------|-----|-------|------|-------|-----|
// |Horizontal sync |0x1D9-0x1F2| 26 |SCLK/2 | 52 |MCLK/5 | 260 |
// |----------------|-----------|-----|-------|------|-------|-----|
// |Back porch |0x1F3-0x00A| 24 |SCLK/2 | 48 |MCLK/5 | 240 |
// |(Left Blanking) | | | | | | |
// |----------------|-----------|-----|-------|------|-------|-----|
// |TOTALS | | 342 | | 684 | |3420 |
// -----------------------------------------------------------------
// Analog screen sections in relation to HCounter (H40 mode):
// --------------------------------------------------------------------
// | Screen section | HCounter |Pixel| Pixel |EDCLK| EDCLK |MCLK |
// | (PAL/NTSC H40) | value |clock| clock |ticks|divider|ticks|
// | | |ticks|divider| | | |
// |----------------|---------------|-----|-------|-----|-------|-----|
// |Left border |0x00D-0x019 | 13 |EDCLK/2| 26 |MCLK/4 | 104 |
// |----------------|---------------|-----|-------|-----|-------|-----|
// |Active display |0x01A-0x159 | 320 |EDCLK/2| 640 |MCLK/4 |2560 |
// |----------------|---------------|-----|-------|-----|-------|-----|
// |Right border |0x15A-0x167 | 14 |EDCLK/2| 28 |MCLK/4 | 112 |
// |----------------|---------------|-----|-------|-----|-------|-----|
// |Front porch |0x168-0x16C | 9 |EDCLK/2| 18 |MCLK/4 | 72 |
// |(Right Blanking)|0x1C9-0x1CC | | | | | |
// |----------------|---------------|-----|-------|-----|-------|-----|
// |Horizontal sync |0x1CD.0-0x1D4.5| 7.5 |EDCLK/2| 15 |MCLK/5 | 75 |
// | |0x1D4.5-0x1D5.5| 1 |EDCLK/2| 2 |MCLK/4 | 8 |
// | |0x1D5.5-0x1DC.0| 7.5 |EDCLK/2| 15 |MCLK/5 | 75 |
// | |0x1DD.0 | 1 |EDCLK/2| 2 |MCLK/4 | 8 |
// | |0x1DE.0-0x1E5.5| 7.5 |EDCLK/2| 15 |MCLK/5 | 75 |
// | |0x1E5.5-0x1E6.5| 1 |EDCLK/2| 2 |MCLK/4 | 8 |
// | |0x1E6.5-0x1EC.0| 6.5 |EDCLK/2| 13 |MCLK/5 | 65 |
// | |===============|=====|=======|=====|=======|=====|
// | Subtotal|0x1CD-0x1EC | (32)| | (64)| |(314)|
// |----------------|---------------|-----|-------|-----|-------|-----|
// |Back porch |0x1ED | 1 |EDCLK/2| 2 |MCLK/5 | 10 |
// |(Left Blanking) |0x1EE-0x00C | 31 |EDCLK/2| 62 |MCLK/4 | 248 |
// | |===============|=====|=======|=====|=======|=====|
// | Subtotal|0x1ED-0x00C | (32)| | (64)| |(258)|
// |----------------|---------------|-----|-------|-----|-------|-----|
// |TOTALS | | 420 | | 840 | |3420 |
// --------------------------------------------------------------------
// Analog screen sections in relation to VCounter:
// -------------------------------------------------------------------------------------------
// | Video |NTSC |NTSC |PAL |PAL |
// | Mode |H32/H40(RSx00/11)|H32/H40(RSx00/11)|H32/H40(RSx00/11)|H32/H40(RSx00/11)|
// | |V28 (M2=0) |V30 (M2=1) |V28 (M2=0) |V30 (M2=1) |
// | |Int none(LSMx=*0)|Int none(LSMx=*0)|Int none(LSMx=*0)|Int none(LSMx=*0)|
// | |------------------------------------------------------------------------
// | | VCounter |Line | VCounter |Line | VCounter |Line | VCounter |Line |
// | Screen section | value |count| value |count| value |count| value |count|
// |-----------------|-----------|-----|-----------|-----|-----------|-----|-----------|-----|
// |Active display |0x000-0x0DF| 224 |0x000-0x1FF| 240*|0x000-0x0DF| 224 |0x000-0x0EF| 240 |
// |-----------------|-----------|-----|-----------|-----|-----------|-----|-----------|-----|
// |Bottom border |0x0E0-0x0E7| 8 | | 0 |0x0E0-0x0FF| 32 |0x0F0-0x107| 24 |
// |-----------------|-----------|-----|-----------|-----|-----------|-----|-----------|-----|
// |Bottom blanking |0x0E8-0x0EA| 3 | | 0 |0x100-0x102| 3 |0x108-0x10A| 3 |
// |-----------------|-----------|-----|-----------|-----|-----------|-----|-----------|-----|
// |Vertical sync |0x1E5-0x1E7| 3 | | 0 |0x1CA-0x1CC| 3 |0x1D2-0x1D4| 3 |
// |-----------------|-----------|-----|-----------|-----|-----------|-----|-----------|-----|
// |Top blanking |0x1E8-0x1F4| 13 | | 0 |0x1CD-0x1D9| 13 |0x1D5-0x1E1| 13 |
// |-----------------|-----------|-----|-----------|-----|-----------|-----|-----------|-----|
// |Top border |0x1F5-0x1FF| 11 | | 0 |0x1DA-0x1FF| 38 |0x1E2-0x1FF| 30 |
// |-----------------|-----------|-----|-----------|-----|-----------|-----|-----------|-----|
// |TOTALS | | 262 | | 240*| | 313 | | 313 |
// -------------------------------------------------------------------------------------------
//*When V30 mode and NTSC mode are both active, no border, blanking, or retrace occurs. A
// 30-row display is setup and rendered, however, immediately following the end of the 30th
// row, the 1st row starts again. In addition, the VCounter is never reset, which usually
// happens at the beginning of vertical blanking. Instead, the VCounter continuously counts
// from 0x000-0x1FF, then wraps around back to 0x000 and begins again. Since there are only
// 240 lines output as part of the display, this means the actual line being rendered is
// desynchronized from the VCounter. Digital events such as vblank flags being set/cleared,
// VInt being triggered, the odd flag being toggled, and so forth, still occur at the
// correct VCounter positions they would occur in (IE, the same as PAL mode V30), however,
// since the VCounter has 512 lines per cycle, this means VInt is triggered at a slower
// rate than normal.
All this is confirmed through hardware testing.