PDAC: NV1 DAC and external devices control


On NV1 cards, many display and IO tasks are handled by a separate SGS DAC chip. This chip’s registers are accessed through card’s main MMIO range. Its tasks are:

  • generating video, memory, and audio clocks
  • converting pixel data in memory to analog VGA signals
  • handling the joystick port
  • handling the saturn ports

The MMIO registers

8-bit space nv1-pdac [0x1000]
nv1-mmio 0x609000: PDAC

This range contains DAC registers mapped directly to the MMIO space. Note that DAC is connected to NV1 by an 8-bit bus, so all these registers are in fact effectively 8-bit (with high 24 bits ignored on write, returned as 0 on reads).

This range is always active.

Address Name Description
0x0 PAL_WRITE Palette write index
0x4 PAL_DATA Palette data
0x8 PAL_MASK Palette index mask
0xc PAL_READ Palette read index
0x10 INDEX_LOW indirect DAC register index, low part
0x14 INDEX_HIGH indirect DAC register index, high part
0x18 DATA indirect DAC register data
0x1c GAME_PORT ISA-like game port

The DAC registers

The DAC has a lot of registers, and only a handful are available directly in the MMIO space. Most of its registers are so-called “inner DAC registers”, are selected by a 16-bit index, and can be accessed by indexed data port in MMIO space:

reg32 nv1-pdac-index-low
nv1-pdac 0x10: INDEX_LOW

Stores low 8 bits of the register index to be accessed.

reg32 nv1-pdac-index-high
nv1-pdac 0x14: INDEX_HIGH

Stores high 8 bits of the register index to be accessed.

reg32 nv1-pdac-data
nv1-pdac 0x18: DATA

All accesses to this register are forwarded to nv1-dac register selected by the above two index registers. After every access, the index stored in the index registers is incremented by 1 (with proper carry between high and low part).

The inner DAC registers are:

8-bit space nv1-dac [0x10000]


regs 0x1c-0xff


regs 0x1xx and 0x5xx


regs 0xf0xx

Address Name Description
0x0 VENDOR_ID Vendor ID
0x1 DEVICE_ID Device ID
0x2 REVISION_ID Revision ID
0x4 CONFIG_0 Configuration 0
0x5 CONFIG_1 Configuration 1
0x6 DDCIN DDC1 input
0x8 PAL_INDEX Current palette index
0x9 PAL_STATE Palette state
0xa PAL_RED Palette inflight red value
0xb PAL_GREEN Palette inflight green value
0xc POWERDOWN_0 Subunit powerdown 0
0xd POWERDOWN_1 Subunit powerdown 1
0xe POWERDOWN_2 Subunit powerdown 2
0x10+i*0x4 (i<nv1-dac-clock) PLL_M[i] PLL M parameter
0x11+i*0x4 (i<nv1-dac-clock) PLL_N[i] PLL N parameter
0x12+i*0x4 (i<nv1-dac-clock) PLL_O[i] PLL O parameter
0x13+i*0x4 (i<nv1-dac-clock) PLL_P[i] PLL P parameter
0x300+i*0x2 (i<2) SATURN_PORT_DATA[i] Saturn port data
0x301+i*0x2 (i<2) SATURN_PORT_MODE[i] Saturn port mode

DAC identification

The DAC can be identified by reading the 3 ID registers:

reg8 nv1-dac-vendor-id
nv1-dac 0x0: VENDOR_ID

The DAC vendor ID:

  • 0x44: SGS


reg8 nv1-dac-device-id
nv1-dac 0x1: DEVICE_ID

The DAC device ID:

  • 0x32: STG1732
  • 0x64: STG1764


reg8 nv1-dac-revision-id
nv1-dac 0x2: REVISION_ID

The DAC revision ID. No idea about the values, mine is 0xb2 [STG1764].


Powerdown registers

Parts of DAC functionality can be powered down when not used via powerdown registers:

reg8 nv1-dac-powerdown-0
nv1-dac 0xc: POWERDOWN_0
  • bits 0-2: ???
  • bit 3: ??? powered down by default by BIOS
  • bits 4-6: ???
  • bit 7: ??? powered down by default by BIOS


RE me

reg8 nv1-dac-powerdown-1
nv1-dac 0xd: POWERDOWN_1
  • bit 0: MPLL - powering that down will permanently hang the card
  • bit 1: VPLL
  • bit 2: APLL
  • bit 3: CRYSTAL - powering that down isn’t a good idea either
  • bits 4-7: ???


RE me

reg8 nv1-dac-powerdown-2
nv1-dac 0xe: POWERDOWN_2
  • bits 0-3: ???


RE me


The DAC contains 3 PLLs, corresponding to the three clocks that NV1 uses:

  • 0: MEMORY, used to control memory and PGRAPH operations
  • 1: AUDIO, used to control PAUDIO operations
  • 2: VIDEO, used to control scanout

Each PLL is controlled by 4 DAC registers:

reg8 nv1-dac-pll-m
nv1-dac 0x10+i*0x4: PLL_M[i] (i<nv1-dac-clock)


write me

reg8 nv1-dac-pll-n
nv1-dac 0x11+i*0x4: PLL_N[i] (i<nv1-dac-clock)


write me

reg8 nv1-dac-pll-o
nv1-dac 0x12+i*0x4: PLL_O[i] (i<nv1-dac-clock)
  • bits 0-3: ???


write me

reg8 nv1-dac-pll-p
nv1-dac 0x13+i*0x4: PLL_P[i] (i<nv1-dac-clock)
  • bits 0-3: ???


write me


write me


The DAC contains two palettes. Each palette consists of 256 entries. Each palette entry consists of three 8-bit values, one for each color.

Two palettes are present for VGA emulation: If a 16-color mode is in use, BIOS can bind palette 0 to the access registers, and palette 1 to display: user will be able to modify palette 0, and BIOS will periodically translate it into palette 1 taking into account the ATC palette remap registers.

The palette is accessed through 3 registers, which behave like VGA palette access registers.

The palette access circuitry has the following state:

  • 8-bit current read/write index
  • current mode: read or write
  • current red and green value, 8-bit each
  • current color: red, green, or blue

The state is stored in the following internal DAC registers:

reg8 nv1-dac-pal-index
nv1-dac 0x8: PAL_INDEX

Stores the current read/write index. Read only.

reg8 nv1-dac-pal-state
nv1-dac 0x9: PAL_STATE
  • bits 0-2: CURRENT_COLOR, read only, one of:
    • 1: RED
    • 2: GREEN
    • 4: BLUE
  • bit 3: SELECT, selects which palette is accessed by the access register
  • bits 4-5: CURRENT_MODE, read only, one of:
    • 0: WRITE
    • 3: READ
  • bit 6: DISPLAY_SELECT, selects which palette is accessed by display pipeline
  • bit 7: WIDTH, selects whether palette values are passed as-is, or converted from/to 6-bit format, one of:
    • 0: FULL, values are passed as-is
    • 1: VGA, all values written to palette cells will be shifted left by 2 bits, and all values read from palette cells will be shifted right by 2 bits, to simulate 6-bit palette cells as used on VGA
reg8 nv1-dac-pal-red
nv1-dac 0xa: PAL_RED

Stores the current red value. Read only.

reg8 nv1-dac-pal-green
nv1-dac 0xb: PAL_GREEN

Stores the current green value. Read only.

The palette access registers are:

reg32 nv1-pdac-pal-write
nv1-pdac 0x0: PAL_WRITE

When written, sets the current mode to write, sets the current index to the written value, and sets the current color to red.

When read, returns the current index.

reg32 nv1-pdac-pal-read
nv1-pdac 0xc: PAL_READ

When written, sets the current mode to read, sets the current index to the written value + 1, and sets the current color to red. When read, returns the current index.

The behavior on reads depends on value of nv1-dac-config-0 bit 4. If it’s to INDEX, the current index is returned. Otherwise, returns the current mode in low 2 bits (same values as in CURRENT_MODE), junk in high 6 bits.

reg32 nv1-pdac-pal-data
nv1-pdac 0x4: PAL_DATA

When written: If the current color is red or green, store the value as the current value for the corresponding color. Otherwise, write the palette entry selected by the current index with the current red and green values, and the written value as the blue value.

When read: read entry (CURRENT_INDEX-1) of palette and return the color selected by current color.

After both read and write, the current color is cycled to the next one (red -> green -> blue -> red). If blue -> red transition happens, current index is increased by one.

Like on VGA, whenever the display pipeline needs a color index looked up, it is first ANDed together with the value of the palette index mask register:

reg32 nv1-pdac-pal-mask
nv1-pdac 0x8: PAL_MASK

Stores the palette index mask. This register is set to 0xff on DAC reset.

DAC config


write me

reg8 nv1-dac-config-0
nv1-dac 0x4: CONFIG_0
  • bits 0-3: ???
  • bit 4: PAL_READ_READ, selects nv1-pdac-pal-read value returned on reads
    • 0: INDEX, current index will be returned
    • 1: MODE, current mode will be returned (like on VGA)
  • bits 5-6: ???


write me

reg8 nv1-dac-config-1
nv1-dac 0x5: CONFIG_1
  • bits 0-4: ???
  • bit 5: ??? writing as 1 causes register to reset to 0
  • bit 6: ???
  • bit 7: ???, read-only, toggling randomly


write me

DDC input

The DAC supports DDC1 input. DDC1 protocol, as opposed to modern I2C-based DDC2 protocol, is fully unidirectional. The monitor continuously sends the entire EDID block in an endless cycle on the ID1 pin, clocked by the VSYNC signal from card. On NV1, the ID1 line is connected to DDCIN pin on the DAC. The raw state of this line is exposed directly as a DAC register:

reg8 nv1-dac-ddcin
nv1-dac 0x6: DDCIN
  • bit 0: Current state of the DDCIN line, read-only

To quickly read the EDID block, software can do bit-banging on the VSYNC line via nv1-pfb-power-sync register.


reg32 nv1-pdac-game-port
nv1-pdac 0x1c: GAME_PORT


write me


write me

Saturn ports

The saturn ports are controlled by simple GPIO:

reg8 nv1-dac-saturn-port-data
nv1-dac 0x300+i*0x2: SATURN_PORT_DATA[i] (i<2)
  • bits 0-6: state of relevant saturn port pin. Read only if configured as input, read-write if configured as output.
reg8 nv1-dac-saturn-port-mode
nv1-dac 0x301+i*0x2: SATURN_PORT_MODE[i] (i<2)
  • bits 0-6: mode of relevant saturn port pin:
    • 0: OUTPUT
    • 1: INPUT

The bit assignments are:

  • 0: DATA[0]
  • 1: DATA[1]
  • 2: DATA[2]
  • 3: DATA[3]
  • 4: SENSE
  • 5: SELECT[1]
  • 6: SELECT[0]


some newer DACs have more functionality?