Video Interface: Difference between revisions

(Updated DITHER_FILTER_ENABLE note about causing vertical banding, which only appears to happen when AA is disabled.)
 
(40 intermediate revisions by 8 users not shown)
Line 2:
 
= Video DAC =
The Video DAC hasuses a 7 bit multiplexed data bus that is used to generatereceives the video signal from the RCP. This allows the N64 to output a 21 bit color output even thouthough internally itthe N64 can dostore 24 bits. Why this lower bit was not used is not explained in any documentation found at this moment.
[[File:N64videosys.png|thumb|Video DAC Bus and waveform. Image from: http://members.optusnet.com.au/eviltim/n64rgb/n64rgb.html]]
 
 
The Video DAC clock runs at 4 times the speed of the internal pixel clock so the multiplexing can happen on the VI bus. This 4 clock process outputs the RGB colors and the VSync, Hsync, Clamp and Csync and is reset using a dsync reset signal. ThisThe video clock is drivenprovided by aone pixelof clockthe provided by thetwo MX8330MX8330s (IC U7)
{| class="wikitable"
|+
Line 63:
|Low
|}
There are 3 different pixelvideo clocks that are used in the N64 for the 3 TV standards: <gallery>
File:MX8330 video maths.png|Mx8330 video clock maths and fselect
</gallery>
Line 69:
|+
!TV Signal Type
!MX8330 Nominal input clock (by definition)
!Pixel Clock
!MX8330 Input clock
!MX8330 FSEL input
!Measured Video Clock
!Clock Maths using datasheet
|-
|NTSC
|14.32MHz (18 × 227.5 ÷ 286)
|48.62Mhz
|14.3Mhz
|HIGH
|48.62Mhz
|((14.3 * 4 )* 17) / 5
|(14.3 * 17) / 5
|-
|PAL
|17734475 Hz
|48.72Mhz
|17.4Mhz
|LOW
|49.56Mhz
|((17.4 * 4 )* 14) / 5
|(17.7 * 14) / 5
|-
|MPAL
|14.30MHz (18 × 227.25 ÷ 286)
|To be advised
|HIGH
|To be advised
|Not yet measured
|To be advised
|(14.3 * 17) / 5
|
|}
 
Line 109:
-n = Default value n at power on
<x:y> = Specifies bits x to y, inclusively</pre>
==== <span style="display:none;">0x0440 0000 - VI_CTRL</code> ====
----
{{#invoke:Register table|head|1200px|VI_CTRL <code>0x0440 0000</code>}}
Line 119:
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0
|-
| — || — || — || — || — || — || — || style="font-size: 7060%;" | DITHER_FILTER_ENABLEDEDITHER_FILTER_ENABLE
{{#invoke:Register table|row|15:8}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || U-0 || RW-0 || RW-0
|-
| colspan="4" | PIXEL_ADVANCE<[3:0>] || KILL_WE || — || colspan="2" | AA_MODE<[1:0>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| TEST_MODE || SERRATE || style="font-size: 70%;" | VBUS_CLOCK_ENABLE || DIVOT_ENABLE || GAMMA_ENABLE || style="font-size: 70%;" | GAMMA_DITHER_ENABLE || colspan="2" | TYPE<[1:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-17 | Undefined | Initialized to <code>0</code>
| 16 | DITHER_FILTER_ENABLEDEDITHER_ENABLE | DitherDedither Enable bit <br>1 {{=}} DitherDedithering (aka "dither filter") is enabled; (normally used for 16-bit color;framebuffers thisto maytry causeto verticalreconstruct bandinga if anti32-aliasingbit isimage. disabledNotice [https://github.com/DragonMinded/libdragonthat this filter only works correctly when <code>AA_MODE</issues/159code> asis seenset here])to <code>00</code>. <br>0 {{=}} Dither filterDedithering is disabled (normally used for 32-bit color)
| 15-12 | PIXEL_ADVANCE<[3:0>] | Use <code>0b0011</code> for most effective behavior on N64. On the iQue Player a pixel advance of <code>0b0011</code> creates video glitches, applications typically use <code>0b0001</code> instead.
| 11 | KILL_WE | Diagnostics only, possibly kills VI DMA writes to line buffers making them safe to access via the test registers.
| 10 | Undefined | Initialized to <code>0</code>
| 9-8 | AA_MODE<[1:0>] | Anti-Alias Mode <br>11 {{=}} AA and resampling disabled, replicate pixels without interpolation <br>10 {{=}} AA disabled, resampling enabled, and operate as if everything is covered <br>01 {{=}} AA enabled, resampling enabled, and only fetches extra lines as needed <br>00 {{=}} AA enabled, resampling enabled, and will always fetch extra lines (required if <code>DEDITHER_ENABLE</code> is 1).
| 7 | TEST_MODE | Diagnostics only, enables usage of the line buffer test registers VI_TEST_ADDR/VI_STAGED_DATA. KILL_WE should also be set to avoid access races between the VI and CPU.
| 7 | TEST_MODE | Diagnostics only
| 6 | SERRATE | Normally enabledRequired if interlacing, otherwisepermitted when progressive, often disabled <br>1 {{=}} Enabled <br>0 {{=}} Disabled
| 5 | VBUS_CLOCK_ENABLE | Vbus Clock Enable <br>1 {{=}} Enabled <br>0 {{=}} Disabled <br>{{spaces|4}}'''''Warning: Always leave disabled!''' Setting this bit enables a second driver, which will output on the same pin as another driver, possibly causing physical console damage.''
| 4 | DIVOT_ENABLE | Fixes minor artifacts left over from anti-aliasing (more details below) <br>1 {{=}} Enabled (usually used if AA is enabled) <br>0 {{=}} Disabled
| 3 | GAMMA_ENABLE | Fixes non-linear gamma in TV screens (more details below) <br>1 {{=}} Enabled <br>0 {{=}} Disabled
| 2 | GAMMA_DITHER_ENABLE | Adds randomized noise to the video output, in the least significant bits to remove mach banding artifacts <br>1 {{=}} Enabled (usually set unless banding artifacts are desired for extra effect) <br>0 {{=}} Disabled
| 1-0 | TYPE<[1:0>] | Video pixel size, also known as color bit depth <br>11 {{=}} 8/8/8/8 (32 bit color) <br>10 {{=}} 5/5/5/3 (16 bit color, technically 18 bits wide) <br>01 {{=}} reserved <br>00 {{=}} blank (no data and no sync, TV screens will either show static or nothing)
}}
'''Extra Details:'''
: '''DEDITHER_ENABLE'''
:: When enabled, the VI will run a de-dithering algorithm, trying to reverse the effects of dithering on each pixel to produce an higher resolution color information on the analog output. This is useful when the framebuffer is 16-bit and has been dithered while drawing. To do so, VI looks at the 8 neighbors around each pixel and perform an error correction; the algorithm used works best with images that have been dithered using the "Magic Square" dithering algorithm (that the RDP can be configured to do). The VI does de-dedithering only on pixels where coverage is full; on pixels with partial coverage, the standard AA algorithm is performed. '''NOTE''': this filter requires <code>AA_MODE</code> to be set to <code>00</code>, otherwise the image is corrupted by vertical streaks ([https://github.com/DragonMinded/libdragon/issues/159 as seen here]).
: '''DIVOT_ENABLE'''
:: When enabled, this feature fixes artifacts that the anti-aliasing algorithm leaves behind. The median color of three neighboring pixels, from any pixels on or next to silhouette edges, is selected to be displayed in place of the center pixel. Effectively removing any one pixel divots that can be seen in some fractal-based terrains. The anti-aliasing function encounters issues when multiple fragments occur on a single pixel. Since this filter is only used on edges, and not the surface of an object, texture details will not be affected. Be aware that bad quality effects can occur when the ''decal line'' rendering mode is used in conjunction with this filter, as the rendering mode generates edges that the filter can detect.
: '''GAMMA_ENABLE'''
:: This feature is used to correct non-linear gamma found in TV screens (although this may have changed in modern TV's). To do this, the feature square roots the linear color space that the rendering pipeline uses. TV screens will raise these color values to the power of 2.2 to 2.4, which leaves a residual gamma behind of around 1.1 to 1.2. This residual value is actually preferred as a gamma slightly above 1.0 will generate more color accurate images when the TV is in darker than normal rooms. When using MPEG or JPG images, the gamma correction is included in the image data, so this feature should be turned off accordingly.
 
==== <span style="display:none;">0x0440 0004 - VI_ORIGIN</code> ====
==== <span style="display:none;">0x0440 0004 - VI_ORIGIN ====
----
{{#invoke:Register table|head|550px|VI_ORIGIN <code>0x0440 0004</code>}}
Line 159 ⟶ 162:
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | ORIGIN<[23:16>]
{{#invoke:Register table|row|15:8}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | ORIGIN<[15:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | ORIGIN<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-24 | Undefined | Initialized to <code>0</code>
| 23-0 | ORIGIN<[23:0>] | RDRAM base address of the video output Frame Buffer. This can be changed as needed to implement double or triple buffering.
}}
'''Extra Details:'''
==== <span style="display:none;">0x0440 0008 - VI_WIDTH</code> ====
: ORIGIN must be a multiple of 8 (i.e. ORIGIN[2:0] must be 0). Otherwise the VI output may be noisy, shifted, or weirdly interleaved.
 
==== <span style="display:none;">0x0440 0008 - VI_WIDTH ====
----
{{#invoke:Register table|head|550px|VI_WIDTH <code>0x0440 0008</code>}}
Line 187 ⟶ 193:
| U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || — || — || — || colspan="4" | WIDTH<[11:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | WIDTH<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-12 | Undefined | Initialized to <code>0</code>
| 11-0 | WIDTH<[11:0>] | This is the width in pixels of the frame buffer if you draw to the frame buffer based on a different width than what is given here the image will drift with each line to the left or right. The common values are 320 and 640, the maximum value is 640. The minimum value depends on the TV set, 160 would probably be a safe minimum but no guarantee4095. The same value would also be used on drawing commands for clipping or scissors. This can also be used with High Res interlacing modes to change the odd and even lines of the frame buffer to be drawn to screen by doubling the width of this value and changing the VI_ORIGIN register to the odd or even field being displayed.
}}
'''Extra Details:'''
==== <span style="display:none;">0x0440 000C - VI_V_INTR</code> ====
: WIDTH must be a multiple of 2 (if 32bpp) or 4 (if 16bpp) such that the number of bytes from one scanline to the next is a multiple of 8. The same caveats about VI_ORIGIN apply here, but incorrect display will only happen on some scanlines.
 
==== <span style="display:none;">0x0440 000C - VI_V_INTR ====
----
{{#invoke:Register table|head|550px|VI_V_INTR <code>0x0440 000C</code>}}
Line 211 ⟶ 220:
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-1 || RW-1
|-
| — || — || — || — || — || — || colspan="2" | V_INTR<[9:8>]
{{#invoke:Register table|row|7:0}}
| RW-1 || RW-1 || RW-1 || RW-1 || RW-1 || RW-1 || RW-1 || RW-1
|-
| colspan="8" | V_INTR<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-10 | Undefined | Initialized to <code>0</code>
| 9-0 | V_INTR<[9:0>] | When VI_V_CURRENT reaches this half-line number, a VI Interrupt is triggered. Usually set to the last line containing pixel data.<br>Default value of <code>0x3FF</code>
}}
==== <span style="display:none;">0x0440 0010 - VI_V_CURRENT</code> ====
----
{{#invoke:Register table|head|550px|VI_V_CURRENT <code>0x0440 0010</code>}}
Line 235 ⟶ 244:
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || style="font-size: 88%;" colspan="2" | V_CURRENT<[9:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | V_CURRENT<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-10 | Undefined | Initialized to <code>0</code>
| 9-0 | V_CURRENT<[9:0>] | The current half line, sampled once per line. Bit 0 is constant for non-interlaced modes. In interlaced modes, bit 0 gives the field number. Writing anything to this register clears the currently triggered VI Interrupt.
}}
==== <span style="display:none;">0x0440 0014 - VI_BURST</code> ====
----
{{#invoke:Register table|head|550px|VI_BURST <code>0x0440 0014</code>}}
Line 251 ⟶ 260:
| U-0 || U-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || — || colspan="6" | BURST_START<[9:4>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="4" | BURST_START<[3:0>] || colspan="4" | VSYNC_WIDTH<[3:0>]
{{#invoke:Register table|row|15:8}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | BURST_WIDTH<[7:0>]
{{#invoke:Register table|row|7:0}}
| RW-1 || RW-1 || RW-0 || RW-1 || RW-0 || RW-0 || RW-0 || RW-1
|-
| colspan="8" | HSYNC_WIDTH<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-30 | Undefined | Initialized to <code>0</code>
| 29-20 | BURST_START<[9:0>] | Start of color burst in pixels from hsync
| 19-16 | VSYNC_WIDTH<[3:0>] | VerticalOne less than the vertical sync widthduration in half lines
| 15-8 | BURST_WIDTH<[7:0>] | Color burst width in pixels
| 7-0 | HSYNC_WIDTH<[7:0>] | Horizontal sync width in pixels<br>Default value of <code>0x01</code>
}}
'''Examples:'''
Line 276 ⟶ 285:
:* horizontal sync width in pixels: 57 (decimal)
:* color burst width in pixels: 34 (decimal)
:* vertical sync width in half lines: 5 (decimal) (and thus 6 half-lines)
:* start of color burst in pixels from h-sync: 62 (decimal)
: PAL @ any resolution is <code>0x0404233A</code>
:* horizontal sync width in pixels: 58 (decimal)
:* color burst width in pixels: 35 (decimal)
:* vertical sync width in half lines: 4 (decimal) (and thus 5 half-lines)
:* start of color burst in pixels from h-sync: 64 (decimal)
 
==== <span style="display:none;">0x0440 0018 - VI_V_SYNC</code> ====
==== <span style="display:none;">0x0440 0018 - VI_V_SYNC ====
----
{{#invoke:Register table|head|550px|VI_V_SYNC <code>0x0440 0018</code>}}
Line 297 ⟶ 307:
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || colspan="2" | V_SYNC<[9:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | V_SYNC<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-10 | Undefined | Initialized to <code>0</code>
| 9-0 | V_SYNC<[9:0>] | TotalOne less than the total number of visible and non-visible half-lines. This should match either NTSC/MPAL (non-interlaced: <code>0x20D525</code>, interlaced: <code>0x20C524</code>) or PAL (non-interlaced: <code>0x271625</code>, interlaced: <code>0x270624</code>)
}}
 
==== <span style="display:none;">0x0440 001C - VI_H_SYNC</code> ====
==== <span style="display:none;">0x0440 001C - VI_H_SYNC ====
----
{{#invoke:Register table|head|550px|VI_H_SYNC <code>0x0440 001C</code>}}
Line 317 ⟶ 328:
| U-0 || U-0 || U-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || — || — || colspan="5" | LEAP<[4:0>]
{{#invoke:Register table|row|15:8}}
| U-0 || U-0 || U-0 || U-0 || RW-1 || RW-1 || RW-1 || RW-1
|-
| — || — || — || — || colspan="4" | H_SYNC<[11:8>]
{{#invoke:Register table|row|7:0}}
| RW-1 || RW-1 || RW-1 || RW-1 || RW-1 || RW-1 || RW-1 || RW-1
|-
| colspan="8" | H_SYNC<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-21 | Undefined | Initialized to <code>0</code>
| 20-16 | LEAP<[4:0>] | 5-bit leap pattern used only for PAL. Should always use standard value of <code>0x15</code>
| 15-12 | Undefined | Initialized to <code>0</code>
| 11-0 | H_SYNC<[11:0>] | TotalOne widthless than the total length of a line,scanline in 1/4 pixel units. Should always use standard values: NTSC (<code>0xC153093</code>), PAL (<code>3177</code>), or PALMPAL (<code>0xC693090</code>)<br>Default value of <code>2047</code> (</code>0x7FF</code>)
}}
 
==== <span style="display:none;">0x0440 0020 - VI_H_SYNC_LEAP</code> ====
'''Extra Details:'''
: LEAP chooses whether to use LEAP_A or LEAP_B on each vsync repeating every five vsyncs. The NTSC default (0) means "always use LEAP_A". The PAL default (0x15) means "alternate using LEAP_B, LEAP_A, LEAP_B, LEAP_A, LEAP_B" and repeat
: Derivation of numbers:
:: NTSC has 227.5 chroma periods per scanline. NTSC N64 has 13.6 VI clocks per chroma period. 227.5 × 13.6 = 3094
:: MPAL has 227.25 chroma periods per scanline. MPAL N64 has 13.6 VI clocks per chroma period. 227.25 x 13.6 = 3090.6
:: PAL (European) has 283.7516 chroma periods per scanline. PAL N64 has 11.2 clocks per chroma period. 283.75 x 11.2 = 3178
: H_SYNC is also used by the RDRAM Interface for refresh timings. As the default is notably shorter than regular video modes, there will be a noticeable impact to memory bandwidth until H_SYNC is configured to a valid video mode.
 
==== <span style="display:none;">0x0440 0020 - VI_H_SYNC_LEAP ====
----
{{#invoke:Register table|head|550px|VI_H_SYNC_LEAP <code>0x0440 0020</code>}}
{{#invoke:Register table|row|31:24}}
| U-0 || U-0 || U-0 || U-0 || URW-0 || URW-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || colspan="24" | LEAP_A<9[11:8>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | LEAP_A<[7:0>]
{{#invoke:Register table|row|15:8}}
| U-0 || U-0 || U-0 || U-0 || URW-0 || URW-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || colspan="24" | LEAP_B<9[11:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | LEAP_B<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-2628 | Undefined | Initialized to <code>0</code>
| 2527-16 | LEAP_A<9[11:0>] | NTSC: Identical to H_SYNC width. PAL: <code>0xC6E3182</code>
| 15-1012 | Undefined | Initialized to <code>0</code>
| 911-0 | LEAP_B<9[11:0>] | NTSC: Identical to H_SYNC width. PAL: <code>0xC6F3183</code>
}}
'''Extra Details:'''
==== <span style="display:none;">0x0440 0024 - VI_H_VIDEO</code> ====
: LEAP_n specifies an alternate scanline length for one scanline during vsync. Values larger than H_SYNC specify the length of the second scanline of vsync. Values smaller than H_SYNC specify the length of the first scanline of vsync and have a variety of undesired side effects, such as skipping one hsync entirely or leaving csync erroneously high for one whole scanline. Serration changes these effects subtly.
: Specifically, a counter is started at the start of vsync. When that counter is equal to LEAP_n, the VI starts or restarts the second scanline of vsync without changing the status of the csync bit.
 
: The default PAL values of LEAP, LEAP_A, and LEAP_B appear to be chosen to add PAL's nominal "one extra chroma period per 625 whole scanlines emitted". Average of 5,6,5,6,5 = 5.4; divide 5.4 by 11.2 VI clocks per chroma period = 1/2 chroma period per field.
 
==== <span style="display:none;">0x0440 0024 - VI_H_VIDEO ====
----
{{#invoke:Register table|head|550px|VI_H_VIDEO <code>0x0440 0024</code>}}
Line 365 ⟶ 391:
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || colspan="2" | H_START<[9:8>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | H_START<[7:0>]
{{#invoke:Register table|row|15:8}}
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || colspan="2" | H_END<[9:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | H_END<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-26 | Undefined | Initialized to <code>0</code>
| 25-16 | H_START<[9:0>] | Start of the active video image, in screen pixels. Typical values: NTSC (<code>0x06C108</code>) or PAL (<code>0x080128</code>)
| 15-10 | Undefined | Initialized to <code>0</code>
| 9-0 | H_END<[9:0>] | End of the active video image, in screen pixels from hsync. Typical values: NTSC (<code>0x2EC748</code>) or PAL (<code>0x300768</code>)
}}
'''Extra Details:'''
==== <span style="display:none;">0x0440 0028 - VI_V_VIDEO</code> ====
: H_START specifies when VI evaluation starts. The screen remains blanked for several pixels afterwards, while the VI loads values from RAM for filtering, even if AA_MODE is set to "no filtering".
: H_END specifies the first black pixel on the right end of each scanline.
 
==== <span style="display:none;">0x0440 0028 - VI_V_VIDEO ====
----
{{#invoke:Register table|head|550px|VI_V_VIDEO <code>0x0440 0028</code>}}
Line 391 ⟶ 421:
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || colspan="2" | V_START<[9:8>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | V_START<[7:0>]
{{#invoke:Register table|row|15:8}}
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || colspan="2" | V_END<[9:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | V_END<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-26 | Undefined | Initialized to <code>0</code>
| 25-16 | V_START<[9:0>] | Start of the active video image, in screen half-lines. Typical values: NTSC (<code>0x025</code>) or PAL (<code>0x05F</code>)
| 15-10 | Undefined | Initialized to <code>0</code>
| 9-0 | V_END<[9:0>] | End of the active video image, in screen half-lines from vsync. Typical values: NTSC (<code>0x1FF</code>) or PAL (<code>0x239</code>)
}}
==== <span style="display:none;">0x0440 002C - VI_V_BURST</code> ====
----
{{#invoke:Register table|head|700px|VI_V_BURST <code>0x0440 002C</code>}}
Line 417 ⟶ 447:
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || style="font-size: 90%;" colspan="2" | V_BURST_START<[9:8>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | V_BURST_START<[7:0>]
{{#invoke:Register table|row|15:8}}
| U-0 || U-0 || U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0
|-
| — || — || — || — || — || — || style="font-size: 90%;" colspan="2" | V_BURST_END<[9:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | V_BURST_END<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-26 | Undefined | Initialized to <code>0</code>
| 25-16 | V_BURST_START<[9:0>] | Start of the color burst enable, in half-lines. Typical values: NTSC (<code>0x00E</code>) or PAL (<code>0x009</code>)
| 15-10 | Undefined | Initialized to <code>0</code>
| 9-0 | V_BURST_END<[9:0>] | End of the color burst enable, in half-lines. Typical values: NTSC (<code>0x204</code>) or PAL (<code>0x26B</code>)
}}
==== <span style="display:none;">0x0440 0030 - VI_X_SCALE</code> ====
----
{{#invoke:Register table|head|550px|VI_X_SCALE <code>0x0440 0030</code>}}
Line 443 ⟶ 473:
| U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || — || — || — || colspan="4" | X_OFFSET<[11:8>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | X_OFFSET<[7:0>]
{{#invoke:Register table|row|15:8}}
| U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || — || — || — || colspan="4" | X_SCALE<[11:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | X_SCALE<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-28 | Undefined | Initialized to <code>0</code>
| 27-16 | X_OFFSET<9[11:0>] | Horizontal subpixel offset ([[#Fixed-Point Format|2.10 format]])
| 15-12 | Undefined | Initialized to <code>0</code>
| 11-0 | X_SCALE<9[11:0>] | 1/horizontal scale up factor (2.10 format)
}}
===== Errata =====
==== <span style="display:none;">0x0440 0034 - VI_Y_SCALE</code> ====
* If [[#0x0440_0000_-_VI_CTRL|AA_MODE]] = 11 (resampling disabled), [[#0x0440_0000_-_VI_CTRL|TYPE]] = 10 (16-bit), X_SCALE is 0x200 or lower, and H_START is less than 128, the VI generates invalid output, consisting of the first 64 pixels from the framebuffer from the current line, then 64 pixels of garbage, and these two repeat for the rest of each scanline
* If X_SCALE is higher than 0x800 (32bpp) or 0xE00 (16bpp), the scaler renders incorrect pixels, with specifics depending on depth. This appears to be due to exceeding the number of VI fetches allocated per scanline.
 
==== <span style="display:none;">0x0440 0034 - VI_Y_SCALE ====
----
{{#invoke:Register table|head|550px|VI_Y_SCALE <code>0x0440 0034</code>}}
Line 469 ⟶ 503:
| U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || — || — || — || colspan="4" | Y_OFFSET<[11:8>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | Y_OFFSET<[7:0>]
{{#invoke:Register table|row|15:8}}
| U-0 || U-0 || U-0 || U-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || — || — || — || colspan="4" | Y_SCALE<[11:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | Y_SCALE<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-28 | Undefined | Initialized to <code>0</code>
| 27-16 | Y_OFFSET<9[11:0>] | Vertical subpixel offset ([[#Fixed-Point Format|2.10 format]])
| 15-12 | Undefined | Initialized to <code>0</code>
| 11-0 | Y_SCALE<9[11:0>] | 1/vertical scale up factor (2.10 format)
}}
===== Erratum =====
==== <span style="display:none;">0x0440 0038 - VI_TEST_ADDR</code> ====
* If Y_SCALE exceeds 0xC00, it instead behaves like a glitchy variation of 3*(0x1000-Y_SCALE)
 
==== <span style="display:none;">0x0440 0038 - VI_TEST_ADDR ====
----
{{#invoke:Register table|head|550px|VI_TEST_ADDR <code>0x0440 0038</code>}}
Line 507 ⟶ 544:
| U-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| — || colspan="7" | TEST_ADDR<[6:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-7 | Undefined | Initialized to <code>0</code>
| 6-0 | TEST_ADDR<[6:0>] | DiagnosticsSets only,the usageline unknownbuffer word address at which VI_STAGED_DATA will read/write data.
}}
==== <span style="display:none;">0x0440 003C - VI_STAGED_DATA</code> ====
----
{{#invoke:Register table|head|550px|VI_STAGED_DATA <code>0x0440 003C</code>}}
Line 519 ⟶ 556:
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | STAGED_DATA<[31:24>]
{{#invoke:Register table|row|23:16}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | STAGED_DATA<[23:16>]
{{#invoke:Register table|row|15:8}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | STAGED_DATA<[15:8>]
{{#invoke:Register table|row|7:0}}
| RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0 || RW-0
|-
| colspan="8" | STAGED_DATA<[7:0>]
{{#invoke:Register table|foot}}
{{#invoke:Register table|definitions
| 31-0 | STAGED_DATA[31:0] | Reads from this register returns 32 bits of line buffer data at the address specified in VI_TEST_ADDR. Writes to this register emplace 32 bits of data into the line buffer at the address specified in VI_TEST_ADDR. Usage requires TEST_MODE to be set in VI_CTRL.
| 31-0 | STAGED_DATA<31:0> | Diagnostics only, usage unknown
}}
= How to use this information =
 
= Fixed-Point Format =
 
[[wikipedia:Fixed-point_arithmetic|Fixed-point]] is a method of representing decimal numbers.
Unlike floating-point numbers, fixed-point numbers allocate a specific number of bits for the integer (X) and
fractional (Y) parts of the number, denoted as "X.Y format" (similar to [[wikipedia:Q_(number_format)|Q-notation]]).
In this format, a certain number of bits are dedicated to the integer part, while the
remaining bits represent the fractional part. For instance, some VI registers employ
the 2.10 format, where two bits are used for the integer part and ten bits are
allocated for the fractional part, resulting in a total of twelve bits.
 
Here are examples of decimals represented in 2.10 format:
 
<math>
\begin{align*}
1\ == &\quad 01\ 0000000000\ \text{(0x400)} \\
0.25\ == &\quad 00\ 0100000000\ \text{(0x100)} \\
0.125\ == &\quad 00\ 0010000000\ \text{(0x80)} \\
\end{align*}
</math>
 
Note that not all decimals can be represented and must be approximated.
For example, in 2.10 format the decimal 3.14 is approximated as 3.1416015625,
or `11 0010010001`. Here's an example of how to convert from the binary to decimal:
 
The integer part is given by adding powers of two, starting at zero and going right to left:
 
<math>
\begin{align*}
\text{Binary:} &\quad 11 \\
\text{Value:} &\quad 1 \times 2^1 + 1 \times 2^0 = 3 \\
\end{align*}
</math>
 
The fractional part is given by adding the inverse of powers of two, staring at one and going left to right:
 
<math>
\begin{align*}
\text{Binary:} &\quad 0010010001 \\
\text{Value:} &\quad \frac{0}{2^1} + \frac{0}{2^2} + \frac{1}{2^3} + \frac{0}{2^4} + \frac{0}{2^5} + \frac{1}{2^6} + \frac{0}{2^7} + \frac{0}{2^8} + \frac{0}{2^9} + \frac{1}{2^{10}} = 0.1416015625 \\
\end{align*}
</math>
 
= How to use this information =
=== Interlace Mode ===
The NTSC (and PAL) standard support interlace mode which is commonly associated with high resolution, but it can be used for more than that.
Line 590 ⟶ 669:
Advanced version of this is to reduce either the height or width and to increase the scaling so it still fits the screen but stretches the image out to fill the screen.
 
[[Category:Motherboard components]]
__FORCETOC__