Releases: Darkone83/XbDiag
Release list
1.0.11 Beta
XbDiag 1.0.11 Beta — Changelog
A big thank you to the original Xbox community for the feedback and testing
that helped shape this release. Your reports, suggestions, and real-world
testing on hardware are what drive XbDiag forward — it is appreciated more
than you know.
New Features
SysInfo — EOS Modchip Detection (SysInfo.cpp)
XbDiag now identifies the EOS LPC BIOS-loader modchip (Team Resurgent /
Darkone) as its own chip rather than reporting it as a Xenium.
EOS is a clean-room design that implements the Xenium banking convention on
purpose — its bank register lives at I/O 0x00EF with the same low-nibble
1-10 encoding — so the existing banking probe matches it exactly as it matches
a genuine Xenium. Banking alone cannot tell the two apart. EOS additionally
decodes I/O 0x00EE and returns a fixed 0x55 there (a Darkone signature
byte; unconditional, read-only, no side effects). A real Xenium's 0x00EE is a
two-bit LED/control field that reads 0x00-0x03 and can never return 0x55.
DetectModchip now reads 0x00EE immediately after the 0x00EF banking probe
matches: 0x55 reports EOS, anything else reports Xenium. The check is one
extra read-only port access on the LPC bus the probe already uses, and it is
the only way to distinguish the two — no other signature separates a clean-room
Xenium-banking chip from the original. A genuine Xenium is unaffected and
reports exactly as before.
SmBusScan — EOS Device and Register Map (SmBusScan.cpp)
The SMBus scanner now recognises the EOS modchip at 7-bit address 0x6E
(sw-shifted 0xDC) as a known device instead of an unidentified ACK. The grid
entry reads "EOS — EOS LPC BIOS-loader modchip (Team Resurgent / Darkone)".
A register descriptor table has been added so the [A] register read labels each
EOS register: MAGIC (0xD8 Darkone signature), firmware version major / minor /
patch, live STATUS and ENGINE state, and the two lock-mask bytes. Labels are
taken directly from the EOS firmware register map. The CRC result and
last-command registers are internal to the update flow and are intentionally
omitted from the scan view — they carry no meaning outside an active update, and
the detail panel shows at most eight registers.
Note that STATUS and ENGINE are live: they reflect what EOS is doing at scan
time, so they will read differently depending on whether the chip is idle,
preloading, or mid-update. MAGIC and the version bytes are the only constant
identifiers.
Controller Test — Configurable Drift Warn Gate (ControllerTest.cpp)
The Drift card now supports a user-adjustable warn threshold to eliminate
false positives. The pass/fail threshold was previously a fixed 4% of full
scale; it is now a configurable gate from 0 to 20%.
The intended workflow: hold a known-good controller and capture the gate from
its measured drift, then test a new or suspect controller against the same
number. A pad is only flagged when it genuinely drifts more than the reference.
Controls on the Drift card: DPAD Up / Down nudge the gate by 1% per press; [Y]
captures the gate from the current measured drift (the worse of the two sticks,
plus a small margin, clamped to the 0-20% window); [X] is unchanged and still
resets the samples. The readout shows the active gate value and its source —
captured, manual, or the fixed default. With the gate left at 0 the card
behaves exactly as before, using the standard 4% threshold, so the change is
opt-in.
The Drift card already sampled raw unfiltered stick values with automatic
baseline capture and ADC jitter nulling; the gate builds on that existing
machinery without altering it.
Files Changed
SysInfo.cppSmBusScan.cppControllerTest.cpp
1.0.10 Beta
XbDiag 1.0.10 Beta — Changelog
A big thank you to the original Xbox community for the feedback and testing
that helped shape this release. Your reports, suggestions, and real-world
testing on hardware are what drive XbDiag forward — it is appreciated more
than you know.
Bug Fixes
SysInfo — Rev 1.6 Ambient Temperature Scaling (SysInfo.cpp)
On rev 1.6 hardware the PIC proxy returns a raw ambient reading that requires
a 0.8x scaling correction before display — the same correction applied by
TempMonitor and referenced in PrometheOS xboxConfig. SysInfo was storing the
raw averaged value directly, causing ambient temperature to read high compared
to every other tool on 1.6 hardware. The correction is applied after averaging
the 3-sample PIC read, inside the PIC-only block — rev 1.0-1.5 ADM1032
readings are unaffected.
TempMonitor — Sensor Wait Message (TempMonitor.cpp)
While the sensor path is being detected or the rev 1.6 PIC accumulator is
filling, the module previously showed raw SMBus NAK strings in red implying
a hardware fault during normal initialisation. Replaced with friendly dim grey
messages centred in the graph area: "Please wait — reading sensor..." when path
is unknown, "Please wait — reading temperature data..." when path is known but
the accumulator has not yet committed.
FileExplorer — Cache Volumes X and Y Now Visible (FileExplorer.cpp)
Cache partitions X: and Y: were silently omitted from the drive list because
FindFirstFile("X:\*") returns INVALID_HANDLE_VALUE on empty volumes. The HDD
drive probe now uses GetFileAttributesA on the root path — the same approach
already used for MU detection — which succeeds on any accessible volume
regardless of whether it contains files.
LCD — Display Detection Regression Fixed (Lcd.cpp)
A regression introduced after 1.0.3 caused the physical LCD display to never
initialise on any hardware. The CerBiosOwnsLCD() function had an
IoCreateSymbolicLink call added to mount E: before reading cerbios.ini. On
systems where E: is already correctly mounted by the kernel this call either
failed with an unexpected return code or introduced a conflicting symlink,
corrupting SMBus state before the detection probe fired. The function has been
reverted to the 1.0.3 approach of opening cerbios.ini directly with
CreateFileA, which returns false immediately on non-CerBIOS installs with no
bus interaction. The call site has also been corrected to pass
(BYTE)(LCD_ADDR >> 1) rather than the hardcoded literal 0x3C.
LCD — FTP Progress Bar (Lcd.cpp)
The PUT transfer progress bar previously used GetTickCount() % 101 to generate
a fake percentage, producing a jittery sweep that conveyed no real information.
PUT and DIR transfers now show a ping-pong spinner where a '>' character
bounces smoothly across the bar at 120ms per step, making it clear a transfer
is active without implying false progress. GET transfers retain the deterministic
fill bar with real percentage since the total file size is known.
The refresh rate values for interlaced modes in the mode table were incorrectly
set to the field rate rather than the frame rate. 480i and 1080i are now 30Hz
and 576i PAL is now 25Hz — reflecting the correct frame rate that the hardware
delivers. Progressive modes 480p and 720p remain at 60Hz and 50Hz respectively.
VideoInfo — Interlaced Mode Refresh Rates Corrected (VideoInfo.cpp)
The refresh rate values for interlaced modes in the mode table were incorrectly
set to the field rate rather than the frame rate. 480i and 1080i are now 30Hz
and 576i PAL is now 25Hz — reflecting the correct frame rate that the hardware
delivers. Progressive modes 480p and 720p remain at 60Hz and 50Hz respectively.
VideoInfo — NKPatcher Detection Path Corrected (VideoInfo.cpp)
The NKPatcher detection check was looking for C:\nkpatcher\ which lives on real
Partition2 — invisible when ShadowC is active and C:\ is remapped to a virtual
image. Detection now checks E:\NKP11, E:\NKP10, and E:\NKPatcher\ — all known
NKPatcher config directories — covering Rocky5 1.1, Rocky5 1.0, and standalone
installs across all versions.
VideoInfo — NKPatcher Warning Overlay Not Rendering (VideoInfo.cpp)
The warning overlay was not visible despite the correct code path executing.
RenderNKWarn was calling the main Render() function which completed its own
BeginScene/EndScene/Present cycle, leaving all overlay draws outside any active
scene. RenderNKWarn now manages its own full scene independently — BeginScene,
DrawPageChrome, dim backdrop, warning card, text, EndScene, Present.
FileExplorer — ShadowC Real C Partition Access (FileExplorer.cpp)
The ShadowC detection check shared the same incorrect C:\nkpatcher\ path.
Detection updated to probe E:\NKP11, E:\NKP10, and E:\NKPatcher\ for full
version coverage. After detection, IoDeleteSymbolicLink clears any stale N:
mapping then IoCreateSymbolicLink maps N: to \Device\Harddisk0\Partition14
(Rocky5 NKP11 ACTUAL_C_DRIVE) with fallback to Partition6 for older configs.
Mount is verified by checking N:\ accessibility before adding to the drive list.
About — Typo and Calibration-Aware Centering (AboutScreen.cpp)
"Bonb Bloke" corrected to "Bomb Bloke". All centred text updated to use the
calibrated area centre rather than raw SW / 2, so items remain properly centred
on displays with non-zero margin settings. Left-aligned text and horizontal rules
use g_marginL / g_marginR rather than the hardcoded LM constant.
Improvements
SysInfo — BIOS Row Removed (SysInfo.cpp / SysInfo.h / HttpRptSrv.cpp)
The BIOS row previously showed "See VideoInfo" which confused users expecting
a version string. Reliable BIOS detection requires parsing mod-chip-specific
flash layouts which differ across Evox, X2, Cerbios, and retail — not safe to
scan blindly. The row has been removed from the on-screen display, text export,
HTTP server BIOS card, and SysSnapshot struct entirely. biosVer removed from
SysData.
SysInfo — TSOP Info Button Label (SysInfo.cpp)
[X] Flash renamed to [X] TSOP Info across all hint bar states. The previous
label implied a flash write operation, causing user confusion.
SysInfo — Encoder ID Row Removed (SysInfo.cpp)
The ENC ID row showing the raw encoder chip ID byte in hex has been removed
from the VIDEO section. The encoder name already conveys the relevant
information and the raw ID byte was consuming valuable vertical space in the
right column. encId removed from SysData. The local encId variable used
internally for board revision detection and encoder name lookup is retained.
HddInfo — Security Status Display (HddInfo.cpp / HddInfo.h)
The two-row SUPPORT: YES/NO + LOCKED: YES/NO display has been replaced with a
single SECURITY row giving a meaningful status: Not Supported, Not Enabled,
Locked, or Enabled / Unlocked. Not Enabled is shown in white — it is entirely
normal for hardmodded consoles with replacement HDDs which ship without security
enabled. secEnabled (word 128 bit 1) added to HddData. Report export updated.
HddInfo — Total Partition Size in Bar (HddInfo.cpp)
The total partition size is now drawn centred inside each partition usage bar,
giving an at-a-glance capacity reference alongside the free space label.
HddInfo — Partition Size in MB Below 1GB (HddInfo.cpp)
Partitions smaller than 1GB now display their total and free values in MB rather
than as a fractional GB figure. 820 MB is clearer than 0.8 GB, particularly for
the small system partitions C, X, Y, and Z on a stock drive.
HddInfo — Partition Cluster Size Validation (HddInfo.cpp / HddInfo.h)
Each partition now displays its cluster size alongside the free space label using
XGetDiskClusterSizeA. Cluster size is validated against the partition total using
standard FATX guidance — 16KB clusters up to 256GB, 32KB up to 512GB, doubling
per power of two thereafter. Valid sizes are shown in green, undersized
configurations in amber. Cluster data is also included in the text export with an
[UNDERSIZED] flag where applicable.
VideoInfo — Xcalibur 1080i Unblocked (VideoInfo.cpp)
Rev 1.6 Xcalibur hardware previously had 1080i hard-blocked with "NO XCALIBUR
MAP". The kernel programs the Xcalibur encoder internally during mode switches
without needing userspace register writes. Xcalibur 1080i is now treated
identically to Conexant 1080i, marked EXPERIMENTAL in amber and added to the
selectable mode list.
VideoInfo — Mode Test Respects Calibration Data (VideoInfo.cpp)
The mode test overlay was drawn at a hardcoded position relative to the raw
screen edge, causing hint text and the mode list to be cut off on overscanned
displays even when calibration data was present. The overlay now anchors to
g_marginB so its position respects screen.set calibration settings.
Update — Changelog Scroll Speed Control (Update.cpp)
The changelog scroll now responds to the left thumbstick Y axis. Pushing up
increases scroll speed up to 8x, pulling down reverses scroll. [BLACK] toggles
pause and resume — the hint bar updates dynamically. [A] is unchanged.
Screen Calibration — Default Margins Corrected (ScreenCalib.cpp)
ApplyDefaults previously set g_marginL and g_marginR to LM (48px) causing the
chrome to be unnecessarily inset on modern displays and xemu. Defaults are now
zero horizontal margins and natural CONTENT_Y / BOT_BAR_Y for vertical — full
resolution out of the box. CRT users who need overscan compensation run
calibration and save their own settings.
Screen Calibration — Input Anti-Fire Guard (DiagMenu.cpp)
Returning from calibration via [A] confirm could immediately trigger a menu
selection on the next frame because the button release was not awaited. DiagMenu
now spins on PumpInput() + Sleep(10) until...
1.0.9 Beta
XbDiag 1.0.9 Beta — Changelog
New Features
HddSmart — Vendor SMART Database (HddSmartDB.hpp / HddSmart.cpp / HddSmart.h)
A self-contained vendor SMART attribute database replacing the previous flat
name table. Attribute raw values are now decoded into human-readable strings
instead of being displayed as raw hex bytes. The database is implemented as a
single .hpp file included exclusively by HddSmart.cpp — no additional
translation unit or linker entry required.
Architecture — three-layer lookup
- Vendor prefix table — model string prefix match, first match wins. Covers 99 prefixes across 20 vendor/controller families.
- Default attribute table — de facto standard attribute meanings used by the vast majority of drives regardless of vendor. 40 entries covering all commonly reported IDs.
- Fallback — unknown attributes display as
Attr 0xXXwith full 6-byte hex raw value.
Raw format decode (RawFmt enum — 12 types)
| Format | Output example | Basis |
|---|---|---|
| RF_HEX | 00 00 00 2B 00 00 | Opaque/vendor-specific fallback |
| RF_COUNT32 | 8760 | Lower 32-bit plain decimal |
| RF_HOURS | 8760h | Lower 24 bits — matches smartmontools raw24(raw8) |
| RF_MINUTES | 146h 0m | Lower 32 bits ÷ 60 — matches min2hour |
| RF_SECONDS | 2h 3m 4s | Lower 32 bits in seconds — matches sec2hour |
| RF_TEMP | 43C (22/55) | Byte[0]=current°C, bytes[2/3]=min/max with smartmontools sanity gate |
| RF_SECTORS | 12 sct | Lower 16 bits |
| RF_PERCENT | 87% | Byte[0] as percentage |
| RF_RAW16 | 4391 | Lower 16 bits — Seagate error rate style |
| RF_RAW16_OPT16 | 0 (2100) | Lower 16 primary + upper 16 in parens if nonzero — matches raw16(raw16) |
| RF_RAW16_AVG16 | 450ms avg:445ms | Spin-up time ms + optional average — matches raw16(avg16) |
| RF_GIB | 3200 GiB | Lower 32 bits labelled GiB for SSD lifetime writes/reads |
0xA8 and 0xC7 are particularly relevant on original Xbox hardware where
20-year-old IDE cables and IDE-to-SATA adapters of varying quality are the
most common source of bus errors.
Vendor coverage (99 prefixes, 20 tables)
HDD families: Seagate (all ST), WD (all Caviar/colour lines), Samsung SpinPoint (SP/HD), IBM/early Hitachi Deskstar (DTLA/IC35), Hitachi/HGST (HDS/HDT/HUA/HTE), Toshiba 2.5" MK (power-on in minutes), Toshiba 3.5" DT/MD/MG (power-on in hours), Fujitsu (MHT/MHV/MHS/MHY/MHZ — original Xbox OEM), Maxtor DiamondMax (6Y/6L/7Y/7L — OEM Xbox era), Quantum Fireball.
SSD controller families: Samsung (own controller — 840/850/860/870), Intel (SSDSA/SSDSC), Crucial/Micron (CT/MTFD — Marvell/Silicon Motion), SandForce (OCZ/Kingston HyperX/Corsair Force/ADATA SP/Mushkin), Phison (Kingston A400/UV/PNY/Patriot/Team Group), Silicon Motion (ADATA SU/SPCC/Transcend/Gigabyte/KingFast/KingSpec/Intenso), Marvell (SanDisk/WD SSD/Plextor), SK Hynix (HFS/HFM).
Export updated
Column header renamed from RAW VALUE to VALUE. Decoded value shown in the
export alongside the data, matching the on-screen display. Raw hex is preserved
in the export for attributes using RF_HEX where the decode is intentionally
opaque.
Stress Test — Fan Speed Control (StressTest.cpp / StressTestCPU.cpp / StressTest.h)
Manual fan speed override added as a step in the CPU stress test startup wizard. The SMC is fully overridden using the correct two-register PIC protocol confirmed by xboxdevwiki.
Startup wizard flow
IDLE →[A]→ THRESHOLD →[A]→ FAN →[A]→ CONFIRM →[LT+RT]→ RUNNING
Back navigation: [B] from FAN returns to THRESHOLD, [B] from THRESHOLD
returns to IDLE.
Fan Speed overlay (SSTATE_FAN)
- AUTO / MANUAL mode pills (green = auto, orange = manual) toggled with
[X] - In MANUAL mode:
[LT]/[RT]step fan target in 5% increments (0–100%) - Big percentage readout with left/right arrow hints when in MANUAL mode
- AUTO mode shows "SMC controls fan speed" message
[A]applies and proceeds to CONFIRM;[B]cancels and returns to THRESHOLD
PIC register protocol (xboxdevwiki)
Per the xboxdevwiki PIC register table, fan override requires two writes in sequence — writing only to the speed register is silently ignored:
reg 0x05 = fan mode: 0 = automatic (SMC), 1 = custom speed from reg 0x06
reg 0x06 = fan speed: 0..50 (multiply by 2 for 0–100%)
Both registers are written every 500ms (render tick rate) during SSTATE_RUNNING to maintain the override against the SMC's continuous thermal management loop, which updates the fan registers independently and would otherwise reclaim control between writes.
On module exit ([B] from IDLE), ST_CPU_FanRelease() writes 0x05=0 and
0x06=0 to restore SMC automatic fan control.
StressTest.h — new enum value
SSTATE_FAN added between SSTATE_THRESHOLD and SSTATE_CONFIRM.
SSTATE_THRESHOLD and SSTATE_FAN added to the anythingRunning guard —
card navigation is blocked while either overlay is open.
New public API (StressTestCPU.h)
void ST_CPU_FanToggleAuto(); // toggle AUTO ↔ MANUAL
void ST_CPU_FanStep(int delta);// ±1 step (5%), MANUAL only
void ST_CPU_FanApply(); // write PIC regs 0x05+0x06, proceed
void ST_CPU_FanCancel(); // revert to AUTO, no PIC write
void ST_CPU_FanRelease(); // restore SMC control on module exit
bool ST_CPU_FanIsAuto(); // query mode for input gating
int ST_CPU_FanGetPct(); // query current target percentage
Improvements
ControllerTest — Layout (ControllerTest.cpp)
- Trigger bars moved alongside the port status strip (same vertical band,
left/right flanking) — freed space allows sticks, D-pad, and face buttons
to fit without clipping below
BOT_BAR_Y = 416 - Trigger bar label moved to the right of the bar to clear the top chrome
- All Y constants tightened to the new 358px usable height:
Y_TRIG=34,Y_META=108,Y_STICK=170,Y_DPAD=Y_FACE=298 - Diamond bottom lands at y≈408 — 8px clearance above bottom bar
AboutScreen — Credit Card Centering and Fact Ticker (AboutScreen.cpp)
- Logo + name block now centered vertically within each credit card using a
computed block height (
LOGO_DISP_H + 6 + LINE_H) — previously a fixed offset from card top caused visual misalignment - Fact ticker repositioned from hardcoded
BOT_BAR_Y - 24(which overlapped the card bottoms at the newBOT_BAR_Y = 416) to dynamically computed center of the gap between card bottom and panel bottom
Bug Fixes
Stress Test — Fan Not Released on Thermal Abort (StressTestCPU.cpp)
When the thermal abort fired, s_state was set to SSTATE_IDLE and
s_thermalAbort flagged, but ST_CPU_FanRelease() was never called. The fan
remained locked at the manual PIC target (both reg 0x05 in manual mode and
reg 0x06 at the set speed) while the CPU was already over threshold and the
SMC could not compensate. ST_CPU_FanRelease() is now called immediately in
the abort branch so the SMC resumes thermal fan control the moment the abort
is detected.
Stress Test — Confirm Overlay Shows No Settings Summary (StressTestCPU.cpp)
DrawConfirmOverlay previously showed only a generic "START CPU STRESS TEST?"
prompt with no recap of the wizard configuration. After stepping through two
picker screens the user had no way to review their choices before committing.
The overlay now shows the configured abort temperature (colour-coded
green / orange / red) and fan mode (AUTO in green, MANUAL XX% in orange)
above the LT+RT hold prompt.
Stress Test — AutoRun Inherits Manual Fan State (StressTest.cpp)
StressTest_AutoRun() bypasses the interactive wizard and writes directly to
SSTATE_RUNNING. If a prior interactive session left s_fanAuto = false (a
manual fan target active), that override would persist into the headless run
with no mechanism to re-apply or release it. ST_CPU_FanRelease() is now
called at the top of AutoRun to guarantee SMC fan control regardless of
prior session state.
HddInfo — SMART Tab Scroll Never Resets (HddInfo.cpp)
HddSmart_ResetScroll() was declared, implemented, and documented in
HddSmart.h as needing to be called from HddInfo when switching to the SMART
tab, but the call was never wired. The scroll position carried over from the
previous visit every time. The call is now made at the s_view = VIEW_SMART
transition.
StressTestGPU — strlen Build Constraint Violation (StressTestGPU.cpp)
strlen(cs_vsSource) was used to compute the vertex shader assembly source
length in CS_CreateVS(). While functionally safe on a compile-time string,
this violated the no-CRT build constraint. Replaced with StrLen().
XbSet — Float-to-i...
1.0.8 Beta
XbDiag 1.0.8 Beta — Changelog
New Features
Web Dashboard — HttpRptSrv (HttpRptSrv.cpp / HttpRptSrv.h)
A background HTTP server running on port 80, started automatically at boot
alongside the FTP server. No user interaction required — the server is always
available while XbDiag is running. Access from any browser on the same network
via http://<xbox-ip>/.
Architecture
- Single-threaded, polled once per frame via
HttpRptSrv_Poll()in the main loop - Non-blocking
select()with zero timeout — never stalls the frame loop - One connection served per frame. Response body sent in 4KB chunks
- HTTP/1.0,
Connection: close. Single 128KB response buffer - Network stack (XNet/Winsock) brought up by the update checker before
HttpRptSrv_Start()is called — no duplicate init - Socket bound using
SO_REUSEADDRasDWORD,INADDR_ANY— mirrors the
FTP server socket pattern exactly - Settings save uses
GET /save?KEY=val&...query string encoding — avoids
HTTP/1.0 POST body parsing limitations entirely
Pages
/sysinfo — Live hardware snapshot mirroring the System Info module.
Two-column card layout on desktop, single column on mobile. Live stress test
status banner and per-test data cards (CPU temp/fan, RAM sweeps/errors,
GPU loops/FPS) appear automatically when a stress test is running. Page
auto-refreshes every 30 seconds.
/report — Report file viewer. Auto-detects the first existing report file
on D:\. Smarter empty state — checks whether XbDiag.set exists and
tailors the prompt accordingly. File switcher pills link to all text exports.
/settings — Full XbSet editor. CSS toggle switches for all 11 module and
stress toggles, hour/minute spinners for all three stress durations, loops
counter, and the two run option toggles. Sticky save bar always visible while
scrolling. Save via GET /save writes D:\XbDiag.set by calling
XbSet_SaveSettings() directly — identical format and write path to the
on-screen editor. Save result banner (green/red) shown on redirect back.
Export files section at the bottom lists all XbDiag output files with download
links for binary files (bios.bin, eeprom.bin).
/about — About page. XbDiag logo as a hero image, version string from
Update_GetLocalVersion(), platform info, tool description, and Team
Resurgent / Darkone83 / Darkone Customs branding logos embedded as base64 PNG.
/download?f=<filename> — Binary file download. Streams files of any size
in 4KB chunks with Content-Disposition: attachment. No FTP required for
binary exports.
Design
- Dark dashboard aesthetic —
#06080Fbackground,#50DCFFcyan accents,
#50DC64green,#FFA028orange - Inter (sans-serif) for UI chrome and labels, JetBrains Mono for values and
report viewer - Animated background grid, pulsing logo ring animation, blinking ONLINE
status indicator, glowing value text shadows, CSS-only toggle switches with
animated knobs - Fully responsive — two-column card layout on desktop, single column on
mobile. Tested on iOS Safari - All assets (CSS, fonts via Google Fonts CDN, images) fully self-contained
in the HTTP response — no separate file serving required - Team branding logos embedded as base64 PNG — no filesystem dependency
main.cpp hooks (3 lines)
#include "HttpRptSrv.h"
HttpRptSrv_Start(); // after Update_StartBootCheck()
HttpRptSrv_Poll(); // alongside FtpServ_Tick() in main loopSysInfo accessor added
SysInfo_GetSnapshot(SysSnapshot& out) exposes all SysData fields as const
char pointers for the web server. Returns false if data not yet loaded.
Improvements
DiagCommon — CRT Title Safe Area (DiagCommon.h / DiagCommon.cpp)
BOT_BAR_Hincreased from30.fto64.f;BOT_BAR_Yraised from
450.fto416.f- Places bottom bar hint text at design-space y≈443 — within the XDK-specified
7.5% title safe boundary (y < 444 at 480 design units) on all CRT displays - Top and bottom bars continue to bleed to physical screen edges; only content
positioning is affected - All modules using
BOT_BAR_Yas their content lower limit automatically gain
34px of additional usable vertical space — zero module code changes required - Title text in
DrawPageChromecorrected from hardcodedSW - 10.fto
SW - LMto respect the right content margin on all display types g_overscanX/g_overscanYglobals andDiagCommon_SetOverscan()removed —
overscan compensation is now baked into the layout constants directly,
eliminating the__ftol2_sselinker error that the runtime approach caused
HddSmart — Scrolling (HddSmart.cpp)
- SMART attribute table now scrolls with
[DPAD UP]/[DPAD DOWN] - Visible row count calculated dynamically from available content area:
Ftoi((BOT_BAR_Y - firstRowY) / LH2)— currently 19 rows at the updated
BOT_BAR_Y = 416 - Drives with fewer than 19 attributes show no scroll indicators; behaviour
is identical to before for those drives ^ moreindicator right-aligned in the header row when scrolled down from topv N moreindicator below the last visible row showing remaining count- Proportional scrollbar on the right edge (3px track + thumb)
s_smartScrollRstflag resets scroll to top on view entry — call
HddSmart_ResetScroll()from HddInfo when switching to the SMART tab- Critical attribute rows (reallocated sectors, pending sectors, uncorrectable
sectors with non-zero raw values) now highlight in dark red with attribute
name drawn inCOL_RED— more visually distinct than the previous grey - File-scope
SmartRowstruct ands_smartRows[]array replace the per-frame
local allocation; all declarations hoisted to function top for C89 compliance
Update — Changelog Box Clipping (Update.cpp)
- Fixed text bleeding above and below the changelog frame borders on scroll
- Draw condition tightened from partial-overlap check to strict containment:
lines only render whenlineY >= CT + 2.f && lineY + LINE_H <= CT + CH - Prevents partial lines drawing into the box border, the title label area
above, and the bottom bar below — clean entry and exit on both edges as the
auto-scroll cycles
Files Changed
HttpRptSrv.h(new)HttpRptSrv.cpp(new)SysInfo.hSysInfo.cppDiagCommon.hDiagCommon.cppHddSmart.cppUpdate.cppmain.cpp
1.0.7 Beta
Note: 1.0.7 Beta needs to be installed manually due to how the updater processes
XbDiag 1.0.7 Beta — Changelog
Bug Fixes
SysInfo — Softmod hardware freeze on entry (DiagCommon.cpp)
- Fixed a 100%-reproducible hang at "Reading data..." on softmodded consoles.
- Root cause: softmod exploits hijack execution mid-game and can leave the nForce SMBus controller with a stuck in-progress transaction.
HalReadSMBusValue's internal retry loop has no hard timeout — it spins indefinitely if the controller never clears, causing a permanent freeze before any hardware data is read. - Fix: added
SMBusControllerReset()toDiagCommon.cpp. Writes0xFFto the nForce SMBus Global Status register at I/O0xC000(W1C — clears all pending/error/busy bits), then stalls 2ms for the bus to settle. Called once at the top ofReadSysData()before any SMBus probing begins. Safe and a no-op on hardware that is already idle. KeStallExecutionProcessorconsolidated into the sharedextern "C"block inDiagCommon.cpp.
SysInfo — Hard crash on entry on 1.6 hardware (SysInfo.cpp)
- Fixed a hard crash at "Reading hardware..." affecting all 1.6 boards regardless of boot method.
- Root cause:
DetectBoardRevision()performed a raw MMIO dereference at0xFD101000(NV2A PFB block) to read DRAM strap bits distinguishing 1.6 from 1.6b. D3D context teardown from the dashboard leaves the PFB block in a state where this read triggers a machine check, causing a hard reset. - Fix: removed the EMRS dereference entirely. All P2L boards now report
"1.6". The 1.6 vs 1.6b distinction (Samsung vs Hynix DRAM) is cosmetic — both are functionally identical for all diagnostic purposes.
SysInfo — BIOS dump writing to wrong path (SysInfo.cpp)
- Fixed
DumpBios()writingbios.binto the current drive root rather thanD:. CreateFileA("\\bios.bin", ...)resolves relative to the XBE launch drive which may not beD:. Changed to explicit"D:\\bios.bin"matching all other flat export paths in XbDiag.
StressTestRAM — Overscan layout issues (StressTestRAM.cpp)
- Phase label text overflowing the left panel boundary on standard TVs — all 11 phase label strings shortened to fit within the narrowed column.
COL_SPLITnudged from300to310giving the left panel additional breathing room.GRID_LMoffset reduced from+30to+24to compensate, keeping the right grid balanced.- Idle hint string shortened to reduce bottom bar crowding.
New Features
SysInfo — Hardware Registers panel (SysInfo.cpp)
- New
[BLACK]overlay panel: Hardware Registers. Opens on demand,[A]refreshes live,[BLACK]closes. - Left — IDE Bus Master (BAR4 @
0xFF60): Reads BM Command (0xFF60), BM Status (0xFF62), and PRD table address (0xFF64). Decodes ACTIVE, INTR, D0/D1 capability bits individually. Summary uses INTR and PRD as DMA evidence — MCPX programs DMA without ATA SET FEATURES so capability bits 5/6 are unreliable. - Right — NVNet NIC I/O (
0xE000–0xE007): Raw 8-byte read. All-zero expected without full driver init. Displayed with contextual note. - Right — SMBus BAR2 (
0xC200–0xC21F): 32-byte raw research dump of the undocumented secondary SMBus I/O window. Values are static init-time configuration. Board-revision cross-reference note included.
SmBusScan — Controller health panel (SmBusScan.cpp)
- New
[WHITE]overlay panel: SMBus Controller Health + BAR2 Research Dump. Opens on demand,[A]refreshes,[WHITE]closes. - BAR1 section: Reads Global Status (
0xC000) and Global Enable (0xC002). Decodes and color-codes INTER, DEV_ERR, BUS_ERR, FAILED bits individually. - BAR2 section: Raw 32-byte hex dump of
0xC200–0xC21Fas two rows of 16. Non-zero bytes highlighted white.
Stress Test — GPU Stress card (StressTestGPU.cpp / StressTestGPU.h)
- New third stress card: GPU. Navigate with
[Left]/[Right]alongside the existing CPU and RAM cards. - Runs the Crystalline Grotto scene (CrystalScene) as a continuous NV2A GPU workload: ~344K crystal tri submissions per frame across 16 DOT3/cubemap render passes, ~110K cave mesh tri submissions (drawn 3x), 120 billboarded fog quads. Pushes fill-rate, texture bandwidth, and vertex throughput simultaneously.
- Scene loops every 20 seconds. Total elapsed time, loop count, live FPS, peak FPS, min FPS, CPU temp, and fan speed displayed in a two-row overlay strip at the bottom of the screen.
- Abort: hold
[Back]+[A]for 5 seconds — same UX as CPU and RAM cards. LT+RT confirm gate before starting. - Textures loaded from
D:\tex\(crystal_n.dds,crystal_cube.dds,rock.dds) with procedural fallbacks if files are absent. - CrystalScene code is fully self-contained within
StressTestGPU.cpp— no separate CrystalScene dependency.
XbSet — GPU Stress automation (XbSet.cpp / XbSet.h)
- GPU stress test added to XbSet automation:
GPUSTRESS=0/1,GPU_HRS=N,GPU_MIN=Nsettings. - GPU stress runs headlessly for the configured duration, loops the scene, and reports peak FPS, min FPS, scene loop count, and pass/fail result to
D:\XbDiag.txt. - Settings UI updated with GPU STRESS toggle, GPU HOURS, and GPU MINS rows. Settings list now scrolls — all rows accessible regardless of screen height.
Update — XBA archive-based update delivery (Update.cpp)
- Update flow now downloads a single
update.xbaarchive rather than individual files. - Archive is extracted to
D:\via the built-in XBA engine, which handles directory creation, CRC verification, and multi-codec decompression. All assets (XBE, textures, and any future additions) are delivered in one atomic operation. - Temp archive (
D:\update.xba) is always deleted after extraction whether it succeeds or fails. XbDiag.veris still downloaded last as a commit marker — only written on successful extraction.- Adding new assets to a future update requires only rebuilding
update.xbaon the server — no code changes needed. - Extraction progress displayed using the existing progress bar. Status label distinguishes download phase from extraction phase.
Improvements
SmBusScan — Known device table corrections (SmBusScan.cpp)
- EEPROM (
0x54): Chip type corrected from93LC56(SPI) to24LC-compatible(I2C). MAC offsets corrected from0xEA–0xEFto0x40–0x45. Added0xA8–0xAB=HDD key. Count updated 5→8. - PIC16L (
0x10) register descriptors: Expanded from 3 to 7 entries. Added0x09CPU temp,0x0AMB temp,0x10fan speed readback,0x06fan mode. - ADM1032 (
0x4C) register descriptors: Corrected high limit registers, added fractional byte0x10and THERM limit0x19. Count updated 4→8. - Dead code removed:
s_regs_smcwas defined but never wired — removed.
TempMonitor — Xyclops 1.6 SMC handling (TempMonitor.cpp)
- The SMC on 1.6 hardware is Xyclops (8051 core), not PIC16LC63A. Xyclops does not implement temperature registers at
0x09/0x0A— confirmed NAK on all tested 1.6 hardware. - Previously showed a generic red
"PIC NOT RESPONDING"error. Now shows an informational grey"N/A — Xyclops SMC detected"overlay with explanation. Sensor divider label updates to"XYCLOPS". Bottom bar shows"Xyclops 1.6 SMC — temp N/A". OnEnter()now resetss_path,s_xyclopsNoTemp, and all PIC accumulator fields — stale state from AutoRun or a previous session no longer carries over.
StressTest — GPU overlay layout (StressTestGPU.cpp)
- GPU stress overlay expanded to two rows to eliminate text overlap at all resolutions.
- Row 1: ELAPSED / LOOPS / FPS / PEAK / MIN — left-anchored with
TW()-based flowing spacing, resolution independent. - Row 2: CPU temp / FAN speed left-anchored, abort hint right-aligned.
- Strip height increased from 26px to 38px; abort hold bar repositioned accordingly.
Research Findings
SMBus BAR2 (0xC200–0xC21F) — first public read
- Confirmed non-trivial, static data on a 1.3 board:
0x70at offset+0x00,0x0Eat offset+0x10. All other bytes zero. - Values do not change with SMBus activity — rules out a transaction log.
- Best hypothesis: static init-time clock/timing configuration written by 2BL.
0x70 = 112maps to approximately 297 kHz at 33 MHz PCI clock — plausible SMBus clock prescaler. - Cross-board validation ongoing. Community encouraged to report BAR2 values with board revision.
IDE Bus Master (BAR4 0xFF62) — MCPX DMA behaviour confirmed
- BM Status capability bits 5/6 not set by MCPX even when DMA is active — confirms MCPX programs DMA without ATA SET FEATURES.
- INTR bit (2) and non-zero PRD address are the reliable DMA-used indicators on Xbox hardware.
Files Changed
DiagCommon.cppSysInfo.cppSmBusScan.cppStressTestRAM.cppTempMonitor.cppStressTest.hStressTest.cppStressTestCPU.cppStressTestGPU.h(new)StressTestGPU.cpp(new)XbSet.hXbSet.cppUpdate.cpp
1.0.6 Beta
Development Note — Stress Test Thermal Soak (Research Ongoing)
CPU stress test thermal soak behaviour is under active research. Current work is focused on validating that the SSE/x87/integer compute mix combined with memory flood interleaving produces consistent platform-wide heat rather than core-local utilisation only.MEM_BURST_CYCLEShas been set to 16 andMEM_BURST_MSto 30 to increase uninterrupted CPU burn time between memory flood bursts.SM_SSE_OUTERhas been bumped from 128 to 256 to extend sustained FP port saturation per outer iteration. Real hardware validation of the new thermal delta is pending.
[1.0.6 Beta]
New Features
MU Utilities Card (FileExplorer.cpp)
[Back+Black]on a Memory Unit entry at the drive root now opens a three-item MU Utilities card instead of immediately prompting to format. Card items: Format, Create Skeleton Key, Create ENDGAME. The hint bar text and overlay hint have been updated accordingly ([Back+Black] MU Utilities).- Card is rendered as a centred modal overlay (300×136 px, dark blue fill, cyan top border) with a navigable cursor (
[DPAD Up/Down],[A]select,[B]cancel).
Skeleton Key MU Creation (FileExplorer.cpp, FileExplorerMU.cpp, FileExplorerMU.h)
- New end-to-end flow for writing a Skeleton Key to a Memory Unit:
- Checks for
D:\resources\SK.xba; if absent, offers to download from server ([A] Download / [B] Cancel). - Downloads
SK.xbavia HTTP GET/xbdiag/resource/SK.xbafromdarkone83.myddns.me:8008with a live KB progress bar. - Confirms format + write (
[A] Create / [B] Cancel), showing a file-count progress bar during extraction and copy. - Reports success (
[B] Close) or a two-line error message (type on line 1, detail on line 2).
- Checks for
ENDGAME MU Creation (FileExplorer.cpp, FileExplorerMU.cpp, FileExplorerMU.h)
- Identical flow to Skeleton Key using
D:\resources\ENDGAME.xba/ server path/xbdiag/resource/ENDGAME.xba. Both assets share the same internal download and create helpers (MU_DownloadXba,MU_CreateFromXba).
XBA Archive Extractor (xba.cpp, xba.h) — new module
- Self-contained XBA extractor supporting v1 (
XBA\x01) and v2 (XBA\x02) archive formats. No CRT; no dynamic allocation; all buffers file-scope static; MSVC 2003 / C89 declaration ordering. - v1 compression: LZ77 (16 KB window), LZSS (32 KB window), x86 pre-filter variants, stored fallback. CRC32 verified against original unfiltered data.
- v2 compression: per-block scheme (block size 64 KB) with stored, LZ77, LZSS, RLE, LZ77+Huffman, and LZSS+Huffman block types; optional whole-file x86 unfilter post-decode. Canonical Huffman codes rebuilt from 256-entry code-length table at decode time.
- Public API:
Xba_Extract(xbaPath, destFolder, progressFn, detailOut, detailLen)— returns typedXbaResultenum;Xba_ResultStr()for human-readable error strings. - Progress callback
XbaProgressFn(filesDone, filesTotal, bytesDone, bytesTotal)drives the SK/EG in-progress overlay bar.
Improvements
MU Format refactor (FileExplorerMU.cpp)
FE_MU_Format()now performs a proper three-step remount sequence: (1)IoDismountVolume+MU_CloseDeviceObjectto flush all pending I/O, (2)MU_CreateDeviceObject+ format, (3) close and reopen the device object to force a clean FAT driver remount before rebinding the drive-letter symlink. Previously skipping the dismount step could leave the volume in a dirty state after subsequent writes.- Extracted
MU_Remount()helper that dismounts and closes the MU volume; called at the end ofMU_CreateFromXbato release the write session and prevent a stale volume object returningERROR_DISK_FULL(112) on the next operation.
Destination picker now shows Memory Units (FileExplorerOps.cpp)
- The copy/move destination picker previously listed only HDD partitions (C/E/F/G/X/Y/Z). It now also enumerates inserted Memory Units (A–H) using
GetFileAttributesAon the MU root (reliable on empty MUs whereFindFirstFilefails). Each MU entry is labelledP1 MMU1…P4 MMU2and stores its drive letter insizeLowfor picker navigation.
MU drive-letter fix in destination picker (FileExplorer.cpp)
- When opening a drive from the picker at root level, the drive letter was previously always read from
pe.name[0]. MU entries now correctly read the letter frompe.sizeLow(set by the picker enumeration), falling back tope.name[0]only for HDD entries wheresizeLowis zero. Affects both directory-open and root-fallback path inFOS_PICK_DEST.
Bug Fixes
Modal input auto-fire guard (FileExplorer.cpp)
- Added
s_muModalSkipInputflag. Whenever any MU modal opens (card, SK prompt, SK confirm, etc.), the first input tick is consumed before the modal begins processing buttons. Prevents analog[A]re-assertion from immediately selecting the first item after the modal opens on the same edge. [A]and[B]are masked out ofs_prevBtnsat the exact tick the card closes or a state transition fires, so the downstream modal or main browser does not see the button as still held.
1.0.5 Beta
XbDiag Changelog
Development Note — March 2026
The CPU stress test thermal soak behaviour is under ongoing research. Current work is focused on validating that the SSE/x87/integer compute mix combined with the memory flood interleaving produces consistent platform-wide heat rather than core-local utilisation only.MEM_BURST_CYCLEShas been set to 16 andMEM_BURST_MSto 30 to increase uninterrupted CPU burn time between memory flood bursts.SM_SSE_OUTERhas been bumped from 128 to 256 to extend sustained FP port saturation per outer iteration. Real hardware validation of the new thermal delta is pending.
1.0.5 Beta — March 2026
Comment Cleanup
All source file comments have been cleaned up and better aligned. Stale comments removed.
StressTestCPU.cpp — CPU MHz Detection Fixes
PCI slot encoding bug corrected and crystal reference constant unified with SysInfo.cpp.
- PCI slot encoding bug fixed:
ULONG slotwas computed as(dev & 0x1F) | ((func & 0x07) << 5)— dev and func bit fields were swapped, causingHalReadWritePCISpaceto target PCI device 0 instead of device 3 (the MCPX). The correct encoding is((dev & 0x1F) << 5) | (func & 0x07). The CPUMPLL register at offset0x6Cwas silently reading garbage on every boot XTAL_HZconstant unified: inline(50000000.0 / 3.0)replaced withstatic const double XTAL_HZ = 16666666.6667matchingSysInfo.cppexactly — both modules now use the identical bit-for-bit crystal reference- FSB calculation cleaned up: spurious
fsb_mhzintermediate removed; calculation now flowsfsb_hz → cpu_mhzin a single expression matchingSysInfo::MeasureCpuMHz()exactly sLabelcorrected: was"ICS + PIC"/"ICS + PIC (v1.6)"— the ICS clock generator is not involved in this detection path at all. Now correctly displays"MCPX PLL + MSR"
SysInfo.cpp — CPU MHz Detection Fixes
Same class of fixes applied to SysInfo.cpp to ensure both modules agree on all hardware configurations.
- PCI slot encoding corrected to
((dev & 0x1F) << 5) | (func & 0x07)inPciRead32()— previously the same dev/func swap bug affected OC detection and NV2A vendor checks XTAL_HZconstant already present and authoritative in this module —StressTestCPU.cppnow matches it exactly
StressMath.cpp / StressMath.h — Stress Test Thermal Tuning
CPU stress kernel and memory flood timing adjusted to maximise sustained FP port saturation and improve thermal delta on upgraded systems.
SM_SSE_OUTERincreased from 128 to 256 — doubles the number of consecutive SSE MULPS/ADDPS passes before the deadline check, keeping the FP multiplier port loaded for longer uninterrupted bursts per outer iterationMEM_BURST_CYCLESset to 16 — memory flood fires less frequently, giving the CPU more uninterrupted compute time between FSB/DRAM pressure eventsMEM_BURST_MSset to 30 — when the burst does fire it runs longer, producing a more meaningful platform heat event without dominating the CPU burn budget
AboutScreen.cpp — Special Thanks Scroller
Cracktro-style rainbow wave scroller added to the About screen.
- Special thanks label
"Special Thanks To:"added as static white text in the gap between the modules list and the lower panel divider - Wave scroller renders immediately below the label — each character rides an independent sine wave position (
amplitude = 7px, spatial frequency0.018 rad/px, temporal frequency2.2 rad/s) producing a fluid per-character wave as the text scrolls - Rainbow colour — full HSV saturation and value, hue offset per character index with a slow time-driven drift so the rainbow animates continuously across the text
- Credits sequence:
Diego -=- Equinox -=- Andr0 -=- Haguero -=- Harcroft -=- Wolfgang von Douchenozzle -=- The XBOX-Scene Discord -=- The OG Xbox Community - Scroll speed 60px/sec, wraps seamlessly when the full text clears the left edge
- All timing is delta-time driven via
GetTickCount()— frame rate independent
1.0.4 Beta
XbDiag Changelog
Development Note — March 2026
CPU detection and clock speed reporting are still being dialled in. MSR-based ratio reading, PLL register interpretation, and CPUID family/model identification across retail Coppermine, Tualatin upgrade, and xemu-hosted configurations are all under active investigation. Results may not be fully accurate on all hardware combinations in this build.The CPU stress test thermal soak behaviour is also under ongoing research. Current work is focused on validating that the SSE/x87/integer compute mix combined with the memory flood interleaving produces consistent platform-wide heat rather than core-local utilisation only. Tuning recommendations for
MEM_BURST_CYCLESandMEM_BURST_MSwill follow once results from real hardware are confirmed.
1.0.4 Beta — March 2026
Keyboard.cpp / Keyboard.h — QWERTY Layout and Overlay Fixes
Row stagger corrected throughout both fullscreen and overlay keyboard modes to match a real QWERTY physical layout.
- Row 3 (ZXCV) stagger corrected from 1.5× to 1.0× indent — the previous value over-indented the bottom row relative to the ASDF row
- Overlay fn row restructured: BKSP moved to the right of the QWERTY row, Enter moved to the right of the ASDF row, bottom strip reduced to CAPS / SPACE / DONE only
- Fullscreen fn row reverted to four keys (CAPS / SPACE / BKSP / DONE) with no Enter — Enter is overlay-only
- Enter label renamed from
"CR"to"Enter"in overlay rendering - Overlay centred at
OV_GRID_X = 123.fwith navigation extended viaOV_COL_BKSP = 10andOV_COL_ENTER = 9sentinel columns - Enter behaviour commits the current line and inserts a new empty line below — consistent with standard text editor behaviour
FileViewer.cpp / FileEdit.cpp / FileEdit.h — Save Pipeline Overhaul
Root cause of silent save failure identified and fixed: s_prev = cur on confirm box open meant BTN_A was still held from the previous frame, causing FV_Edge to fire instantly and complete the save invisibly in one tick.
s_confirmReadyflag added: set false when the confirm box opens, set true only after A is fully released — the confirm prompt now waits for a clean A press before acting- Save combo changed from A (which conflicts with typing) to BACK alone, eliminating the BACK+A interaction that caused ambiguity with the keyboard overlay
s_editLoadedflag added: separates "keyboard visible" from "edit data alive" — dismissing the keyboard with B keeps edits alive and the UNSAVED indicator on screen without destroying the edit session
File format preservation rewritten as a complete architectural fix:
BuildLineInfo()runs beforeBuildLines(), capturing per-logical-line byte offsets and exact terminator lengths (\r\n,\n, or none) from the raw buffer intoFE_LineInfo[]s_rawBuf— a separatemalloc'd clean copy of the file bytes allocated afterReadFileand beforeBuildLines()nulls terminators in-place ins_bufFileEdit_Save()— unchanged lines copy raw bytes verbatim including exact terminators; edited lines write new content followed by the original terminator bytes — mixed\r\n/\nfiles are preserved exactlyFileEdit_GetLastError()returns the Win32 error code captured from a failed save for display in the hint bar
FtpServ.cpp — Client Compatibility Fixes
Several issues identified through testing with FlashFXP, FileZilla, and WinSCP.
- EPSV reply code changed from 522 to 500 — FileZilla was not falling back to PASV on 522; 500 (unrecognised command) triggers correct fallback behaviour
- SIZE command switched from
CreateFiletoGetFileAttributesExA— cheaper, no handle leak risk, consistent with how the file list already queries sizes - SITE → 202, XCRC/XMD5 → 502 — FlashFXP sends these before transfers; correct responses prevent unnecessary retries and connection drops
- Data listen socket now closed after each transfer completes (LIST, RETR, STOR) — previously the socket was left open between transfers causing connection state issues on reconnect
- STOR I/O buffer expanded from 4KB to 64KB — upload speed now symmetric with download speed
- FEAT response cleaned up: MLSD/MLST removed (not implemented), REST STREAM added (correctly advertises resume support)
input.cpp / input.h / ControllerTest.cpp — Controller Type Detection
Duke vs Type-S identification added via XInputGetCapabilities at connect time.
ControllerTypeenum added toinput.h—CT_DUKE(SubTypeXINPUT_DEVSUBTYPE_GC_GAMEPAD),CT_TYPE_S(SubTypeXINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT),CT_UNKNOWNfor wheels, arcade sticks, or unrecognised devicesg_ctrlType[MAX_PORTS]— cached per-port, populated onXInputOpenand cleared toCT_UNKNOWNon disconnectGetControllerType(int port)— public accessor returning the cached type for a given port- Controller type row added to the port status strip in
ControllerTest.cpp— displaysDUKE,TYPE-S, or???in cyan beneath each connected port box; empty ports show nothing
ControllerTest.cpp — Per-Port Disconnect Tracking and Rumble Strip
Per-port connection state tracking added across the main controller view, Stick Test card, and Rumble subcard.
s_wasConn[4]ands_discCount[4]added —s_wasConntracks connection state from the previous tick for edge detection;s_discCountaccumulates a running total of disconnect events seen per port since the module was opened- Disconnect counter increments each time a previously connected port goes away, displayed in red beneath the port status strip when non-zero
- Both arrays reset on module entry via
ControllerTest_OnEnter() - Port status strip added to Rumble subcard (
RenderRumble) — previously the Rumble subcard had no port visibility while the motors were being tested. The same four-box strip (green = connected, dark = disconnected) and Disconnects row from the main view are now rendered at the top of the subcard.cYshifted fromB+160toB+185and the RUMBLE MOTORS header fromB+30toB+58to clear the new strip
Update.cpp / Update.h — Self-Hosted Update Server and Changelog Display
Update server migrated from raw.githubusercontent.com to a self-hosted endpoint, and changelog display added to the update screen.
- Host changed to
darkone83.myddns.meon port 8008 — all version checks, XBE downloads, and changelog fetches now go through the dedicated update server rather than the GitHub raw CDN Update_SetPaths(const char* xbeDir)added — install path is passed in frommain.cppat launch rather than hardcoded, allowing XbDiag to write the downloaded XBE back to whatever folder it was launched from- Background boot check (
Update_StartBootCheck(),Update_IsCheckComplete(),Update_BootFoundUpdate()) — on startupmain.cppkicks off a silent version check while the rest of the initialisation completes. If a newer version is found the app jumps directly to the Update screen instead of the main menu - Changelog fetch (
FetchChangelog(),GET /xbdiag/log.chg) — when entering the Update screen after a successful version check (or when the boot check already has a result), the remote changelog is fetched and displayed in the lower panel with automatic scrolling at 80ms per tick. Scroll resets to the top on wrap-around s_changelog[4096]— 4KB receive buffer; content is stripped of HTTP headers before display
When returning from the FileViewer, START held during exit was seen by the FileExplorer tick on the very next frame, causing an unintended FTP server toggle. Fixed by syncing s_prevBtns = GetButtons() immediately after FileViewer returns control, consuming the held state before the main input loop runs.
1.0.3 Beta
XbDiag Changelog
Development Note — March 2026 CPU detection and clock speed reporting are still being dialled in. MSR-based ratio reading, PLL register interpretation, and CPUID family/model identification across retail Coppermine, Tualatin upgrade, and xemu-hosted configurations are all under active investigation. Results may not be fully accurate on all hardware combinations in this build.
The CPU stress test thermal soak behaviour is also under ongoing research. Current work is focused on validating that the SSE/x87/integer compute mix combined with the memory flood interleaving produces consistent platform-wide heat rather than core-local utilisation only. Tuning recommendations for
MEM_BURST_CYCLESandMEM_BURST_MSwill follow once results from real hardware are confirmed.
1.0.3 Beta — March 2026
font.cpp / font.h — Lowercase Glyph Support
Added 26 lowercase glyph bitmaps (a–z) to the g_font[] array. FindGlyph() previously folded all a-z input to A-Z unconditionally — that fold is removed. Lowercase characters are now looked up directly, with a fallback to the corresponding uppercase glyph only if a lowercase entry is missing. g_fontCount recalculates automatically via sizeof. No call sites changed, no header changes, all existing uppercase strings continue to work exactly as before.
Descenders (g, j, p, q, y) use row 6 of the 5×7 grid, rendering visually shorter than cap height — standard behaviour for a small bitmap font at this resolution.
ControllerTest.cpp — Rumble Port Status Strip
The Rumble subcard (RenderRumble) was missing the port status strip that the main controller view already had. Added the same four-box strip (green = connected, dark = disconnected) plus the "Disconnects:" count row beneath it, using identical geometry (PBW=46, PGAP=6, centred at X_MID). cY shifted from B+160 to B+185 and the "RUMBLE MOTORS" section header from B+30 to B+58 to clear the new strip.
ControllerTest.cpp — Trigger Dead-Zone Card (Stick Test tab 3)
A fourth tab, TRIGGERS, added to the Stick Test card ([Left/Right] to cycle as before). Two vertical bars (left = LT, right = RT) display live pressure 0–255 with tri-colour fill (green → orange → red). The bottom portion of each bar shows a dark red dead-zone band with a bright red threshold line at 30/255.
Stats accumulated per session:
- Live value — current raw reading displayed below each bar
- Min / Max — lowest and highest values seen since entry or last reset
- PASSES DZ (green) — minimum was inside dead-zone but maximum broke through
- IN DZ (red) — maximum never exceeded threshold; trigger does not actuate
[X] resets min/max. Stats reset on re-entry to the Stick Test card. Tab strip per-tab width reduced from 100px to 88px to fit four tabs at the same screen width.
FileExplorer.cpp / FileExplorerOps.cpp — New Folder (R3)
FE_Ops_MkDir(name) added to FileExplorerOps.cpp. Builds the full path from the current directory, calls CreateDirectoryA, reloads the directory listing, and repositions the cursor to the newly created folder. FileExplorer.cpp opens the virtual keyboard on R3 press, routes the confirmed name through OnMkdirDone, and guards the tick loop while the keyboard is active. Hint string updated with [R3] New Folder.
FileExplorer.cpp / FileViewer.cpp / FileViewer.h — File Viewer (L3)
New FileViewer.cpp / FileViewer.h module — read-only viewer for .txt and .csv files, opened from the file explorer with L3 on a compatible file.
malloc'd buffer on open, 512KB cap, freed on exit via both normal and error pathsBuildLines()walks the buffer once, replaces\r\n/\nwith\0in-place, and wraps long lines by pointing segment entries into the existing buffer — no additional allocations- Controls: D-pad up/down = 1 line, LT/RT = page, B = exit and free
- Scroll bar, line counter (
1–21 / N), truncation warning at 512KB, continuation indent on wrapped lines FileViewer_IsActive()guard added toFileExplorer_Tickalongside the keyboard guard
HddBench.cpp — Benchmark Accuracy and Label Consistency
- Seq read path corrected:
BenchStartRead()now opens withFILE_FLAG_NO_BUFFERING | FILE_FLAG_SEQUENTIAL_SCAN. The export header already saidFILE_FLAG_NO_BUFFERINGbut the code was using buffered I/O. Implementation and label now agree. - Fallback file size fix:
BENCH_READloop and progress display callGetFileSize()at the start of the case and use the result (capped atBENCH_FILE_SIZE) as the loop target. In fallback (read-only) mode a source file smaller than 64MB no longer shows incorrect progress or a distorted MB/s number. - CACHE renamed to BUF RD: render label, export header, and export result line all updated. The repeated-block test probes drive buffer behaviour — it is not sustained throughput.
- FS WR export description updated: now reads
buffered write + FlushFileBuffers (practical sustained write)— explicit about flush overhead being included. - Inline cleanup path fix: three
DeleteFileA(BENCH_FILE)calls inBenchTickcompletion paths replaced withDeleteFileA(s_bench.readSrc[0] ? s_bench.readSrc : BENCH_FILE).BenchCleanup()was already correct; the inline paths were not.
StressMath.cpp / StressMath.h — Memory Flood Integration
CPUStress() now interleaves MemFlood_Timed() bursts to broaden the thermal soak from core-local compute to whole-platform FSB/DRAM/northbridge load.
- Every
MEM_BURST_CYCLEScompute iterations aMEM_BURST_MSMemFlood_Timed()pass fires against the 2MBsm_membufbuffer — well outside L2 on all Xbox CPU variants - Default:
MEM_BURST_CYCLES = 8,MEM_BURST_MS = 50— targets ~70% compute / ~30% memory flood - Both constants declared in
StressMath.has tunable values with inline tuning guidance MemFlood_Timed()four-phase rotation unchanged: sequential write, sequential read, strided read (defeats hardware prefetcher), dual-stream copy
1.0.2 Beta — March 2026
Architecture — Major Module Refactoring
All large monolithic .cpp files split into focused sub-modules.
| Original file | Split into |
|---|---|
| HddInfo.cpp | HddInfo.cpp · HddSmart.cpp · HddBench.cpp |
| EepromView.cpp | EepromView.cpp · EepromCrypto.cpp · EepromSettings.cpp · EepromRepair.cpp |
| FileExplorer.cpp | FileExplorer.cpp · FileExplorerMU.cpp · FileExplorerOps.cpp |
| StressTest.cpp | StressTest.cpp · StressTestCPU.cpp · StressTestRAM.cpp |
All new files added to XbDiag.vcxproj and XbDiag.vcxproj.filters.
StressMath.cpp — CPU Stress Kernel Overhaul
Previous x87 FFT kernel achieved ~40–60% measured load. FFT butterfly dependency chains serialise the FP pipeline and fninit in FourComplexSquareSweep serialised the full FPU pipeline once per block. New kernel uses dual-chain SSE1 MULPS/ADDPS targeting the Coppermine's separate FP-MUL and FP-ADD dispatch ports simultaneously.
- Two MULPS chains (
xmm0*xmm4,xmm1*xmm5) and two ADDPS chains (xmm2+xmm6,xmm3+xmm7) dispatch in pairs each cycle - Working set 16KB — exactly half of Coppermine's 32KB L1, ensuring zero cache miss overhead
SM_SSE_OUTER = 128passes betweenGetTickCount()checks (~0.9ms at 733MHz)CPUStress()restructured: SSE passes dominate (~85%), followed by one x87 FFT cycle and oneIntegerStress()pass per outer iterationfninitremoved fromFourComplexSquareSweep- Tualatin compatible — SSE1 encoding identical on Coppermine and Tualatin
ControllerTest.cpp — Trigger Dead-Zone Card (initial add)
(See 1.0.3 — this feature was first introduced in 1.0.2 and expanded in 1.0.3.)
SD/HD Readability and Clipping Fixes
Font_SetSD(bool) and Font_GetAdvance() added. SD mode uses 6.5px advance with scanline-safe dot height and alpha-blended shadow. HD stays at 6.0px. Font_SetSD() called post-InitD3D() in main.cpp. g_isTrueInterlaced flag set for NTSC 480i and PAL 576i only. Per-module SD clipping fixes in RamTest.cpp, TempMonitor.cpp, StressTest.cpp, AboutScreen.cpp, and EepromView.cpp.
1.0.1 Beta — March 2026
SysInfo.cpp
CPU speed — TSC replaced with PLL:
1.0.2 Beta
XbDiag Changelog
1.0.2 Beta — March 2026
Architecture — Major Module Refactoring
All large monolithic .cpp files have been split into focused sub-modules. This reduces per-file compile times, improves code organisation, and makes individual subsystems independently testable. The public API surface of each module is unchanged.
| Original file | Split into |
|---|---|
| HddInfo.cpp | HddInfo.cpp · HddSmart.cpp · HddBench.cpp |
| EepromView.cpp | EepromView.cpp · EepromCrypto.cpp · EepromSettings.cpp · EepromRepair.cpp |
| FileExplorer.cpp | FileExplorer.cpp · FileExplorerMU.cpp · FileExplorerOps.cpp |
| StressTest.cpp | StressTest.cpp · StressTestCPU.cpp · StressTestRAM.cpp |
HddInfo split:
HddInfo.cpp/.h— core load, render, export,OnEnter,Tick,AutoRunHddSmart.cpp/.h— SMART attribute name table and renderHddBench.cpp/.h— sequential read/write and random seek benchmark engine
EepromView split:
EepromView.cpp/.h— core hex/decoded view, state machine,EepromView_Reload()EepromCrypto.cpp/.h—EepCrypto_Decrypt()andEepCrypto_Encrypt()as pure functionsEepromSettings.cpp/.h— TZ table, field editing,EepromSettings_RecalcChecksums(),EepromSettings_GetUtcTzBlock()EepromRepair.cpp/.h— validator diagnostics,EepromRepair_BuildDiag(), repair apply, restore from bin
FileExplorer split:
FileExplorer.cpp/.h— core directory loading, render, tick, FTP integration,GoUp()FileExplorerMU.cpp/.h—FE_MU_MountAll()(HDD partitions + Memory Units),FE_MU_Format()FileExplorerOps.cpp/.h— clipboard, destination picker,FE_Ops_Start/Tick/Snap/DrawPicker/EnterSelected/DeleteRecursive()
StressTest split:
StressTest.cpp/.h— shared state,HandleInput,Tick,AutoRuncoordinationStressTestCPU.cpp/.h—ST_CPU_TakeSample(),ST_CPU_ReadMHz(),ST_CPU_Render(), all CPU render functions and sensor logicStressTestRAM.cpp/.h— 11-phase moving-inversions RAM engine,ST_RAM_OnStart/Stop/Step/Render(),RamStress_AutoRun()
All new files added to XbDiag.vcxproj and XbDiag.vcxproj.filters.
StressMath.cpp — CPU Stress Kernel Overhaul
Problem: The previous x87 FFT kernel achieved ~40–60% measured CPU load. FFT butterfly dependency chains serialise the FP pipeline — each output feeds the next stage input, so the Coppermine's OOO engine exhausts independent work and stalls on 4-cycle latencies. GetTickCount() was called every 8 FFT cycles introducing integer pipeline stalls inside the burn window. fninit at the start of each FourComplexSquareSweep block serialised the entire FPU pipeline once per block.
New kernel — dual-chain SSE1 MULPS/ADDPS:
The Coppermine PIII has separate FP-MUL and FP-ADD dispatch ports. MULPS and ADDPS target these ports independently and can execute simultaneously when operands are independent.
- Two MULPS chains (
xmm0*xmm4,xmm1*xmm5) target FP-MUL; two ADDPS chains (xmm2+xmm6,xmm3+xmm7) target FP-ADD — all four dispatch simultaneously in pairs - Three rounds of 4 ops per 64-byte block hide the 5-cycle MULPS and 4-cycle ADDPS latencies across loop iterations
- Working set: 16KB (
SM_SSE_PASS) — exactly half of the Coppermine's 32KB L1 D-cache, ensuring all MOVAPS accesses hit L1 with zero miss overhead SM_SSE_OUTER = 128passes betweenGetTickCount()checks (~0.9ms at 733MHz); no deadline check inside the inner loop
CPUStress() restructured: SM_SSE_OUTER SSE passes dominate each outer iteration (~85% of clock budget). One complete x87 FFT cycle and one IntegerStress() pass follow. GetTickCount() is called once per outer iteration only.
fninit removed from FourComplexSquareSweep — it was serialising the full FPU pipeline once per 64-byte block with no benefit.
Tualatin compatibility: SSE1 encoding is identical on Coppermine and Tualatin. No changes needed for CPU upgrade variants from 733 MHz through 1400 MHz.
ControllerTest.cpp — Trigger Dead-Zone Card
A fourth tab, TRIGGERS, added to the Stick Test card ([Left/Right] to cycle as before).
Two large vertical bars (80×220px) display live LT and RT pressure. The bottom portion of each bar is filled with a dark red dead-zone band (threshold: 30/255) with a bright red threshold line. The fill colour transitions green → orange → red with pressure value.
Stats accumulated per session:
- Live value — current raw reading (0–255) displayed below each bar
- Min / Max — lowest and highest values recorded since entry or last reset
- PASSES DZ (green) — minimum was inside dead-zone but maximum broke through cleanly
- IN DZ (red) — maximum never exceeded the threshold; trigger does not actuate
[X] resets Min/Max. Stats reset on re-entry to the Stick Test card. The tab strip per-tab width reduced from 100px to 88px to fit four tabs at the same screen width.
SD/HD Readability and Clipping Fixes
font.h/.cpp: Font_SetSD(bool) and Font_GetAdvance() — SD mode uses 6.5px advance with scanline-safe dot height and soft shadow. HD uses 6.0px advance. Font_SetSD() called post-InitD3D() in main.cpp.
DiagCommon.h/.cpp: g_isTrueInterlaced flag (NTSC 480i and PAL 576i only). TW() uses Font_GetAdvance(). DrawPageChrome hint truncation is badge-aware.
Per-module SD clipping fixes:
RamTest.cpp— right-panel legend strings shortened, left-panel quick hint single-space separatorsTempMonitor.cpp— poll hint right-aligned left of badgeStressTest.cpp— status text draw order fixed (drawn after MHz panel so panel background does not paint over it)AboutScreen.cpp— modules list split to 3 linesEepromView.cpp— HEX view column constants corrected (HEX_B8_X,HEX_ASC_X), decoded view hint strings shortened, bottom bar hint fixed
CPU/GPU MHz math: Both SysInfo.cpp and StressTest.cpp now use the exact crystal constant 50000000.0/3.0 with double-precision arithmetic. GPU PLL in SysInfo.cpp also updated to use the correct 16666667 Hz crystal reference.
1.0.1 Beta — March 2026
SysInfo.cpp
CPU speed: TSC replaced with PLL register read
MeasureCpuMHz() previously used RDTSC over a 300ms Sleep() window. This blocked SysInfo load for 300ms on every entry and gave ±5–10 MHz noise at higher clock speeds on Tualatin upgrades. The new implementation reads the MCPX CPUMPLL register (PCI Bus 0, Dev 3, Fun 0, Offset 0x6C) for the FSB divider/multiplier, and MSR 0x2A bits [27:22] for the CPU ratio. The result is exact, instantaneous, and correct on all Tualatin variants (733 MHz through 1400 MHz). The 300ms startup delay is eliminated.
GPU speed: crystal constant precision fix
ReadGpuMHz() was using 16666 KHz as the NV2A PRAMDAC crystal reference. Corrected to 16666667 Hz for proper precision in the (N × crystal) / (M × 2^P) formula.
StressTest.cpp
CPU speed display: ICS clock generator replaced with PLL
ReadCPUMHz() was polling the ICS clock generator at SMBus 0xD2, which only reports three values (733/800/853 MHz) and NAKs on Tualatin upgrades where the ICS chip may be absent. Replaced with the same CPUMPLL + MSR 0x2A method as SysInfo. The CPUMPLL read is cached on first call.
main.cpp + Lcd.cpp/h (new)
Physical LCD display support added
New Lcd.cpp / Lcd.h module drives a US2066-compatible 20×4 character OLED at SMBus 0x78 (7-bit 0x3C). Detection is silent — if no display is found the module no-ops completely.
Pages (auto-cycle every 5 seconds): Thermal, Clocks, Storage, Network. FTP status page activates automatically when the FTP server is running, showing state, IP:21, current filename, and a progress bar.
Shadow buffer tracks display state and skips SMBus writes for cells that have not changed, reducing bus traffic on stable pages to near zero.
Key combos (hold all three simultaneously):
[START + A + WHITE]— enable/reinitialise display[START + A + BLACK]— disable display
LCD_Begin() called at startup after