Runtime control utility for S3 ViRGE and S3 Trio graphics chips on DOS, without requiring a video BIOS flash. All changes are volatile and reset on reboot.
Built originally to fix the "grey blacks" pedestal bug on the integrated S3 ViRGE/DX in a Toshiba Infinia desktop, then generalized to detect and operate on the broader ViRGE / Trio family.
Author: Daniel Arnold
s3ctl writes directly to undocumented graphics chip registers and changes hardware clock frequencies at runtime. Use it at your own risk. The author makes no warranty, express or implied, that this software is fit for any purpose, free of defects, or safe to run on your hardware.
Specifically, you should understand that:
- The pedestal register (SR1A on ViRGE, SR27 on Trio 3D) is
undocumented in S3's datasheets. Behavior outside of bit 5
(ViRGE) / bit 3 (Trio 3D) is unknown. The
pedestal rawsubcommand bypasses the bit-masking and writes the full byte; do not use it unless you understand what you're doing. - Changing MCLK overclocks (or underclocks) the integrated graphics memory bus. Aggressive overclocks can cause visual corruption, system hangs, and in theory silicon damage from over-temperature operation on passively cooled integrated chips. The 60 MHz hard ceiling is a soft recommendation, not a hardware guarantee.
- The Trio 3D code path has never been tested on real hardware.
- All changes are volatile — a reboot restores factory state — but a hung system that won't POST is a hung system. Have a recovery plan (another machine to debug from, a known-good boot floppy) before experimenting on irreplaceable hardware.
This is research-quality code for vintage hardware that nobody makes anymore. Treat it accordingly.
See the LICENSE file (GPL v3 sections 15 and 16) for
the formal warranty disclaimer and limitation of liability.
- Fix grey blacks on affected S3 chips by clearing the pedestal bit (raised black level) in SR1A or SR27, depending on chip family
- Read and set MCLK (memory clock) at runtime, within a safe range
- Detect the chip through a four-tier strategy (PCI BIOS → CR registers → SR1A probe → manual override), so the utility works even on OEM-integrated parts that block CRTC extended register reads
- Display detailed chip information: family, PCI device ID, VRAM size, color mode, revision, current MCLK and DCLK, all the PLL state, and the pedestal register decoded
Warning
The Trio 3D pedestal path is implemented but UNTESTED on real
hardware. The register info (SR27 bit 3) came from documentation
rather than direct verification. If you have a Trio 3D card and try
s3ctl pedestal off, please report your results — see the project
issues or contact the author.
Add this single line to your AUTOEXEC.BAT:
S3CTL.EXE -q pedestal off
That's it. The -q makes it silent so it doesn't clutter your boot
log, and pedestal off clears the pedestal bit (only the pedestal
bit — other bits in the register are left alone). The fix has to be
reapplied at every boot because the change is volatile.
S3CTL INFO
That detects the chip, dumps the current MCLK, pedestal state, and
(where readable) the VRAM size and color mode. Add -v for the
verbose dump including raw register bytes and the full clock-synth
state.
Arguments are case-insensitive in standard DOS fashion. All of these work identically:
S3CTL INFO
s3ctl info
S3CTL --Chip=Trio3D Pedestal Off
s3ctl /chip:virge -v info
| Command | What it does |
|---|---|
s3ctl [flags] info |
Detect chip, show all readable parameters |
s3ctl [flags] pedestal |
Show pedestal register and decoded bit |
s3ctl [flags] pedestal off |
Clear pedestal bit (true black). Alias: 0 |
s3ctl [flags] pedestal on |
Set pedestal bit (raised). Alias: 1 |
s3ctl [flags] pedestal raw <n> |
Write full pedestal byte (advanced; bypasses bit-masking) |
s3ctl [flags] mclk |
Show current MCLK |
s3ctl [flags] mclk <mhz> |
Set MCLK in MHz (30–60 range enforced) |
There is no mclk reset subcommand. Reboot the machine to
restore your OEM's factory MCLK — that's the only reliable way,
because the published S3 reference value (45 MHz) is not necessarily
what your BIOS programs. The Toshiba Infinia, for example, ships its
integrated ViRGE/DX at ~60 MHz.
| Flag | Purpose |
|---|---|
-q |
Quiet — suppress all output (for AUTOEXEC.BAT) |
-v |
Verbose — extra diagnostic detail |
--chip=NAME |
Override autodetect: virge, trio3d, trio, auto |
/CHIP:NAME |
Alias for --chip= in DOS-conventional form |
| Family | Pedestal control | Status |
|---|---|---|
| S3 ViRGE (all variants: DX, GX, VX, MX, GX2) | SR1A bit 5 | Verified on ViRGE/DX |
| S3 Trio 3D / Trio 3D 2X | SR27 bit 3 | UNTESTED — needs hardware verification |
| S3 Trio 32 / 64 / 64V+ / 64V2 | Unknown | Detected but pedestal not supported. Use pedestal raw to experiment. |
PCI device IDs the tool recognizes (vendor 0x5333):
0x8810, 0x8811, 0x883D, 0x8904, 0x8A01, 0x8A10, 0x8C01.
Source: Linux kernel drivers/video/fbdev/s3fb.c.
If your chip isn't recognized but you know what it is, use
--chip=NAME to force the right path.
- Open Watcom 1.9 or 2.0 (C compiler +
wmake) - DOS or Windows host (or Linux with Open Watcom's Linux port)
C:\WATCOM\OWSETENV.BAT :: set up the Watcom environment
wmake :: build
Or manually:
wcl -bt=dos -ms -os -s -wx -zq -fo=.obj -lm -fe=s3ctl.exe s3ctl.c
The result is a single 16-bit real-mode DOS executable, small memory model, no external dependencies.
The pedestal "grey blacks" issue is caused by a single bit in an S3 sequencer register that raises the DAC's black reference voltage, making dark content look washed out. S3 chips support a configurable pedestal because old NTSC composite video required a 7.5 IRE setup level — but on modern VGA output you usually want it off. The video BIOS programs the bit as part of POST initialization, so the only ways to clear it are: modify the video BIOS (risky and chip-specific), or write the register at every boot (what s3ctl does).
The register and bit differ by chip family:
- ViRGE: SR1A bit 5 — empirically confirmed that only this bit affects visible brightness; sweeping the full 0–255 byte range produces only two distinct states grouped by bit 5
- Trio 3D: SR27 bit 3 — documented but unverified here
s3ctl always does a read-modify-write that touches only the pedestal
bit, leaving the other 7 bits as the BIOS programmed them. A raw
escape hatch is provided for experimentation.
For the full register reference, detection strategy, and history of
how this was figured out, see s3ctl_handoff.md.
Huge thanks to Bits Und Bolts (BuB) at bitsundbolts.com for the foundational research that made this utility possible:
- Fixing the S3 brightness bug — a deep dive into the pedestal-bit BIOS mod — identified the pedestal register on both ViRGE (SR1A) and Trio 3D (SR27), documented the unlock sequence, and explained the NTSC-setup origin of the bit. This is the article s3ctl's Trio 3D path is based on.
- S3 ViRGE BIOS Toolkit
— web-based S3 ViRGE BIOS modification tools, including the
overclocker and the corrected VCO formula
(
VCO = ((M+2)/(N+2)) * 14.318) that s3ctl uses for MCLK calculation. The +2 bias offsets aren't in the raw datasheet formula and would have produced wrong answers without BuB's empirical correction.
The Linux kernel framebuffer driver
drivers/video/fbdev/s3fb.c
was the source of the PCI device ID table and the CR-register
detection logic.
S3 datasheets (ViRGE August 1996, Trio family) are linked from the
Docs/ folder in this repository for reference.
Released under the GNU General Public License v3.0. See the
LICENSE file for the full text.
In short: you're free to use, modify, and redistribute s3ctl, but any modified version you distribute must also be GPL v3 with source available. Patent grants are explicit, and anti-tivoization provisions apply if you ship it embedded in hardware.
Things that are known to be incomplete, unverified, or only tested on one piece of hardware. If you can help close any of these gaps, please do.
| Status | What | Why it matters |
|---|---|---|
| UNTESTED | Trio 3D / Trio 3D 2X pedestal fix (SR27 bit 3) | Code path exists per published documentation but has never run on real Trio 3D hardware. Could be wrong. |
| UNTESTED | All ViRGE variants other than ViRGE/DX | The SR1A bit-5 pedestal control is documented as the same across the family, but only ViRGE/DX (86C375) is empirically verified. |
| UNSUPPORTED | Legacy Trio (32 / 64 / 64V+ / 64V2) pedestal | No public documentation of which register controls the pedestal bit on these chips. The utility detects them but refuses pedestal on/off. |
| PARTIAL | MCLK on non-ViRGE chips | The PLL formula is verified on ViRGE; Trio chips use the same encoding per the datasheet but the MCLK code has not been run against a Trio. |
- The 45 MHz "S3 reference" MCLK is a published value, not a per-machine factory value. There is no way to recover your OEM's factory MCLK programming except by rebooting. The utility prints a soft note when current MCLK differs from reference by more than 5 MHz, but this is informational.
- CRTC extended registers (CR2D, CR2E, CR2F, CR36, CR67) are
inaccessible on some OEM-integrated implementations (e.g. the
Toshiba Infinia returns
0x80for all extended CR reads regardless of the unlock sequence). When this happens the utility falls back to the SR1A probe for detection and reportsn/afor the affected fields ins3ctl info. There is no software workaround. - Setting a new MCLK and reading it back immediately is racy — the PLL takes a "short but variable" time to stabilize per the datasheet. The utility reads back without any delay, so the readback value may briefly be wrong on the edge.
Open an issue at the repository's issue tracker if you encounter any of the following. The more diagnostic detail you can include, the better.
Always useful when filing a bug:
- Your chip family (per
s3ctl info), or the closest description if it isn't recognized - The host machine (motherboard, integrated vs add-in card)
- The full output of
s3ctl -v info— that one line captures the detection tier, PCI device ID, all the CR/SR register bytes, MCLK/DCLK state, and pedestal status
Especially valuable:
- Trio 3D verification — run
s3ctl infoto confirm detection, thens3ctl pedestalto see the SR27 value, thens3ctl pedestal off. Report whether the screen visibly changes (deeper blacks) and whether the readback saysbit 3 = 0. - Legacy Trio pedestal hunting — if you have a Trio 32 /
64 / 64V+ / 64V2, try
s3ctl pedestal raw <byte>with different values (0x00, 0x20, 0x08, 0xFF, etc.) on various sequencer registers —pedestal rawwrites to whatever register the chip family is configured to use. We'd need source code changes to test arbitrary registers; if you're comfortable patchingSR_TRIO_PEDins3ctl.cand rebuilding, please do, and report which register + bit produces a visible black-level change. - Unrecognized PCI device IDs — run
s3ctl -v infoon any S3 card and look for[v] PCI scan: no known S3 device foundin the verbose output. If you can also find the PCI device ID via another tool (e.g.PCISLEEP,PCITREE,PCIDOS), please include it. - Unexpected MCLK values — if
s3ctl inforeports an MCLK significantly different from the S3 reference 45 MHz, that's worth a one-line report (chip family, motherboard, the reported value). It helps build a picture of what OEMs actually ship.
If you discover a pedestal register / bit combination for a chip that isn't currently supported — whether through datasheet archaeology, BIOS modification reverse-engineering, blind probing, or just plain luck — please contribute it back. Even a single verified data point ("Trio64V2/DX: SR?? bit ? clears grey blacks on hardware X") is enough to extend compatibility to thousands of old machines.
What I'd ideally want in a contribution:
- Chip family, sub-variant, and PCI device ID (from
s3ctl -v info) - The register index and bit number that controls the pedestal
- The stock value the BIOS programs (raw byte, before any change)
- The fixed value that produces true black (raw byte, after RMW)
- Whether the change is visible immediately or requires a mode set
- Any side effects you noticed on the other bits in that register
A PR adding the new family to the pedestal_target() dispatch in
s3ctl.c is ideal, but even a comment in an issue with
the above information is enough — I'll wire it in. Document what
you tested and what you didn't, just like the existing Trio 3D
path is marked UNTESTED.
PRs welcome more generally, but please open an issue first to discuss anything non-trivial.