Skip to content

Architecture

Le Khanh Binh edited this page Sep 12, 2026 · 4 revisions

Architecture

ZenMaster is structured as a modular Python package for low-level AMD processor power and performance configuration. This document outlines the module layout, execution flow, CPU identification engine, dynamic core complex die (CCD) fuse detection, socket dispatch matrix, hardware synchronization, and telemetry pipeline.

Module Layout

The package consists of the following components:

Module Responsibility
hardware.py CPUID detection, brand string extraction, and resolution into CpuInfo (architecture, family, type, and numeric identifiers).
runner.py Static hardware mappings: CPU family to socket dispatch, 10 socket opcode tables, and argument query utilities.
mailbox.py Mailbox protocol abstraction: handshake execution, response polling, retry logic, and register triplets for MP1, RSMU, and Server HSMP.
pmtable.py Power Management (PM) table metadata, version hashes, struct buffer sizes, and quintuple transfer command definitions.
apply.py CLI parameter tokenization, multi-token Curve Optimizer packing, 20-bit two's complement scaling, and command dispatch.
smu.py Platform-agnostic SMU facade: backend dispatch, status codes, dynamic CCD fuse detection (get_ccd_count), and direct SMN primitives (read_smn, write_smn).
sensors.py PM table telemetry decoders: read_sensors for limit/value pairs and read_core_sensors for multi-CCD per-core telemetry (replaces legacy table.py; zenmaster.table is preserved as an alias).
linux.py Linux backend: direct PCI root complex host bridge config access (NB_ADDR/NB_DATA), ryzen_smu sysfs transport, and /run/lock/access_pci.lock mutex.
windows.py Windows backend: Microsoft-signed PawnIO kernel driver access via DeviceIoControl and Global\Access_PCI named Win32 mutex.
macos.py macOS backend: legacy port I/O via DirectHW.kext, kext-free IOPCIBridge diagnostic client dispatch, and /tmp/access_pci.lock mutex.
iopci.py Apple IOPCIBridge diagnostic user-client implementation (debug=0x144).
iokit.py IOKit service matching and Mach connection helpers (legacy iokitcore.py is preserved as an alias).
directhw.py IOKit user-client interface for DirectHW.kext port I/O and physical memory mapping.
cli.py Command-line interface parser, output formatters, table rendering, and JSON serialization.
update.py Remote PyPI release checking.
errors.py Typed exception hierarchy: ZenMasterError, BackendUnavailable, SMUNotInitialized, and UnsupportedCPU.

Execution Flow

When an argument is passed to the command-line interface, execution proceeds through distinct hardware abstraction layers:

zenmaster --stapm-limit=15000
        |
   cli.main()           Parse CLI flags, detect processor, check administrative privileges
        |
   apply.apply()        Tokenize arguments, validate values, scale units
        |
   runner.lookup()      Resolve opcode tuples for family: (arg_name, is_mp1, opcode)
        |
   smu.send_arg()       Acquire cross-process PCI mutex, route to active OS backend
        |
   backend._send()      Execute SMU mailbox handshake (clear rsp, write args, trigger msg)
        |
   SMU Response         Poll response register until status code returned (0x01 = OK)

The facade in smu.py dynamically resolves the platform backend at initialization based on platform.system(). Application code interacts strictly with the facade interface without platform branching.


CPU Family Matrix and Architecture Resolution

ZenMaster supports 44 AMD CPU families spanning Zen 1 through Zen 6, forward-compatible Family 27 declarations, enterprise EPYC servers, HEDT Threadripper processors, mobile APUs, and x86 licensed derivatives (zenmaster/hardware.py:149-270).

Architecture Mapping

AMD CPU architectures are indexed by base CPUID family integers:

CPUID Family Architecture Label Scope
23 (0x17) Zen 1 - Zen 2 14nm Summit Ridge through 7nm Matisse and Rome
24 (0x18) Zen 1 derivative Hygon Dhyana C86 enterprise server silicon
25 (0x19) Zen 3 - Zen 4 7nm Vermeer and Milan through 5nm/4nm Raphael and Genoa
26 (0x1A) Zen 5 - Zen 6 4nm/3nm Granite Ridge and Turin through Strix Point, Fire Range, and Medusa
27 (0x1B) Zen 6 Forward-compatible fallback mapping

44 CPU Families Matrix

The table below enumerates all 44 CPU families recognized by _resolve_codename:

Family Codename Architecture CPUID Family CPUID Model Brand String Matching Rule Target Socket Group
SummitRidge Zen 1 - Zen 2 23 1 Default (non-Threadripper, non-EPYC) AM4_V1
Threadripper Zen 1 - Zen 2 23 1 Brand contains "threadripper" AM4_V1
Naples Zen 1 - Zen 2 23 1 Brand contains "epyc" AM4_V1
PinnacleRidge Zen 1 - Zen 2 23 8 Default AM4_V1
Colfax Zen 1 - Zen 2 23 8 Brand contains "threadripper" or "colfax" AM4_V1
RavenRidge Zen 1 - Zen 2 23 17, 18 Model 17 or 18 FT5_FP5_AM4
RavenRidge2 Zen 1 - Zen 2 23 24 Brand contains "raven" FT5_FP5_AM4
Picasso Zen 1 - Zen 2 23 24 Default FT5_FP5_AM4
Pollock Zen 1 - Zen 2 23 32 Brand contains "15e", "15Ce", or "20e" FT5_FP5_AM4
Dali Zen 1 - Zen 2 23 32 Default FT5_FP5_AM4
Rome Zen 1 - Zen 2 23 48, 50-63 Model 48, or models 50-63 without "threadripper" AM4_V2
CastlePeak Zen 1 - Zen 2 23 49, 50-63 Model 49, or models 50-63 with "threadripper" AM4_V2
FireFlight Zen 1 - Zen 2 23 80 Model 80 FT5_FP5_AM4
Renoir Zen 1 - Zen 2 23 96 Model 96 FP6_AM4
Lucienne Zen 1 - Zen 2 23 104 Model 104 FP6_AM4
Matisse Zen 1 - Zen 2 23 113 Model 113 AM4_V2
VanGogh Zen 1 - Zen 2 23 144, 145 Model 144 or 145 (Steam Deck APU) FF3
Mendocino Zen 1 - Zen 2 23 160 Model 160 FT6_FP7_FP8
Dhyana Zen 1 derivative 24 All Hygon C86 Chinese domestic x86 processor AM4_V1
Milan Zen 3 - Zen 4 25 1 Model 1 AM4_V2
Chagall Zen 3 - Zen 4 25 8 Model 8 AM4_V2
StormPeak Zen 3 - Zen 4 25 16-31 Model 24 or models 16-31 with "threadripper" AM5_V1
Genoa Zen 3 - Zen 4 25 16-31 Models 16-31 without "threadripper" AM5_V1
Vermeer Zen 3 - Zen 4 25 32, 33 Model 32 or 33 AM4_V2
Rembrandt Zen 3 - Zen 4 25 63, 64, 68 Models 64, 68 (Model 63 aliased for compatibility) FT6_FP7_FP8
Cezanne_Barcelo Zen 3 - Zen 4 25 80 Model 80 FP6_AM4
DragonRange Zen 3 - Zen 4 25 97 Model 97 with "hx" in brand string AM5_MOBILE
Raphael Zen 3 - Zen 4 25 97 Model 97 without "hx" in brand string AM5_V1
PhoenixPoint Zen 3 - Zen 4 25 116 Model 116 FT6_FP7_FP8
HawkPoint Zen 3 - Zen 4 25 117 Model 117 FT6_FP7_FP8
PhoenixPoint2 Zen 3 - Zen 4 25 120 Model 120 FT6_FP7_FP8
HawkPoint2 Zen 3 - Zen 4 25 124 Model 124 FT6_FP7_FP8
Siena Zen 3 - Zen 4 25 144-159 Models 144 through 159 AM5_V1
Bergamo Zen 3 - Zen 4 25 160-175 Models 160 through 175 AM5_V1
Turin Zen 5 - Zen 6 26 0-15 Models 0 through 15 AM5_V1
TurinDense Zen 5 - Zen 6 26 16-31 Models 16 through 31 AM5_V1
StrixPoint Zen 5 - Zen 6 26 32, 36 Model 32 or 36 FT6_FP7_FP8
FireRange Zen 5 - Zen 6 26 68 Model 68 with "hx" in brand string AM5_FIRERANGE
GraniteRidge Zen 5 - Zen 6 26 68 Model 68 without "hx" in brand string AM5_V1
SonomaValley Zen 5 - Zen 6 26 80-95 Models 80 through 95 or "sonoma" in brand string FT6_FP7_FP8
KrackanPoint Zen 5 - Zen 6 26 96 Model 96 FT6_FP7_FP8
KrackanPoint2 Zen 5 - Zen 6 26 104 Model 104 FT6_FP7_FP8
StrixHalo Zen 5 - Zen 6 26 112 Model 112 FT6_FP7_FP8
Medusa1 Zen 5 - Zen 6 26 128-135 Models 128 through 135 FP10_AM5
OlympicRidge Zen 5 - Zen 6 26 136-143 Models 136 through 143 FP10_AM5
Medusa2 Zen 5 - Zen 6 26 224-227 Models 224 through 227 FP10_AM5

CPU Type Classification

Every detected processor is classified into one of four categories (zenmaster/hardware.py:298-304):

  1. Amd_Desktop_Cpu: Applied to all processors listed in _DESKTOP_FAMILIES. This set encompasses desktop client processors (SummitRidge, PinnacleRidge, Matisse, Vermeer, Raphael, GraniteRidge), HEDT platforms (Threadripper, Colfax, CastlePeak, Chagall, StormPeak), Server EPYC platforms (Naples, Rome, Milan, Genoa, Bergamo, Siena, Turin, TurinDense), and OlympicRidge alongside Dhyana.
  2. Amd_Apu: Applied to all AMD architectures not categorized as desktop silicon, covering monolithic mobile APUs, embedded chips, and handheld designs (VanGogh, Mendocino, StrixPoint, KrackanPoint, StrixHalo).
  3. Intel: Applied whenever the processor vendor string contains "Intel". The ZenMaster CLI explicitly rejects non-AMD hardware.
  4. Unknown: Fallback category for unrecognized architectures.

Platform CPUID Resolution

ZenMaster executes unprivileged CPUID and model resolution across operating systems:

  • Linux (_parse_cpuinfo): Parses /proc/cpuinfo to extract cpu family, model, stepping, and model name.
  • Windows (_parse_processor_identifier): Extracts numeric values from the PROCESSOR_IDENTIFIER environment string (for example, "AMD64 Family 25 Model 97 Stepping 2"), followed by querying the branding string from registry key HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\ProcessorNameString.
  • macOS (_parse_sysctl): Direct libc invocation of sysctlbyname against machdep.cpu.family, machdep.cpu.model, machdep.cpu.stepping, and machdep.cpu.brand_string. CPUID values retrieved via sysctlbyname bypass SMBIOS modifications injected by bootloaders.

Dynamic CCD Fuse Detection

On multi-die AMD processors, core complex die (CCD) counts vary significantly between SKUs sharing identical CPUID family and model numbers. A Ryzen 9 7900X features two active CCDs, whereas a Ryzen 5 7600X features a single CCD despite both reporting Family 25 Model 97.

ZenMaster resolves active CCD topology dynamically by querying hardware fuse registers through the System Management Network (SMN) (zenmaster/smu.py:292-314):

def get_ccd_count(family_int: int = 0, model_int: int = 0) -> int:
    ccd_fuse1 = 0x5D218
    ccd_fuse2 = 0x5D21C
    if family_int == 23 and model_int != 113:
        ccd_fuse1 += 0x40  # 0x5D258
        ccd_fuse2 += 0x40  # 0x5D25C
    present = read_smn(ccd_fuse1)
    down = read_smn(ccd_fuse2)
    disabled = ((down & 0x3F) << 2) | ((present >> 30) & 0x3)
    enabled = ((present >> 22) & 0xFF) & ~disabled
    count = enabled.bit_count()
    return count if count > 0 else 1

SMN Fuse Register Mapping

  • Default mapping (Matisse, Zen 3, Zen 4, Zen 5, Zen 6): 0x0005D218 (ccd_fuse1) and 0x0005D21C (ccd_fuse2).
  • Zen 1 / Zen+ non-Matisse offset (family_int == 23 and model_int != 113): A +0x40 register offset is applied, targeting 0x0005D258 and 0x0005D25C.

Fuse Bitfield Extraction

  1. present reads the physical CCD availability bitmap from ccd_fuse1.
  2. down reads the down-fused disabled CCD bitmap from ccd_fuse2.
  3. disabled = ((down & 0x3F) << 2) | ((present >> 30) & 0x3) extracts down-fused dies across both registers.
  4. enabled = ((present >> 22) & 0xFF) & ~disabled masks active dies against disabled bit positions.
  5. count = enabled.bit_count() counts the active set bits, falling back to 1 if the calculation evaluates to 0 or triggers an OSError.

This count dictates telemetry extraction in zenmaster.sensors, scaling per-core sensor matrices to max(core_count, ccd_count * 8) to prevent index truncation on dual-CCD configurations.


Socket Groups and Opcode Resolution

ZenMaster maps CPU families into 10 distinct socket dispatch tables (zenmaster/runner.py:3-61):

  1. SOCKET_AM4_V1: Summit Ridge, Pinnacle Ridge, Threadripper 1000/2000, Naples, Colfax, Dhyana.
  2. SOCKET_FT5_FP5_AM4: Raven Ridge, Raven Ridge 2, Picasso, Dali, Pollock, FireFlight.
  3. SOCKET_AM4_V2: Rome, Castle Peak, Matisse, Milan, Chagall, Vermeer.
  4. SOCKET_FP6_AM4: Renoir, Lucienne, Cezanne / Barcelo.
  5. SOCKET_FF3: VanGogh (Steam Deck custom APU).
  6. SOCKET_FT6_FP7_FP8: Mendocino, Rembrandt, Phoenix Point, Hawk Point, Sonoma Valley, Strix Point, Krackan Point, Strix Halo.
  7. SOCKET_AM5_V1: Raphael, Storm Peak, Genoa, Bergamo, Siena, Turin, Turin Dense, Granite Ridge.
  8. SOCKET_AM5_MOBILE: Dragon Range (Ryzen 7045HX series).
  9. SOCKET_AM5_FIRERANGE: Fire Range (Ryzen 9000HX series).
  10. SOCKET_FP10_AM5: Medusa 1, Olympic Ridge, Medusa 2 (Server HSMP mailbox interface).

Each table entry maps an argument name to a tuple containing the mailbox flag and opcode: (arg_name: str, is_mp1: bool, opcode: int). When is_mp1 is True, the opcode routes to the MP1 mailbox. When False, it routes to the RSMU mailbox.

VRM Opcode Inversion on Mobile Desktop Silicon

Mobile enthusiast desktop-replacement silicons Dragon Range and Fire Range invert the VRM current control opcodes:

Tuning Parameter Dragon Range (AM5_MOBILE) Fire Range (AM5_FIRERANGE)
vrm-current (TDC) MP1 Opcode 0x3c MP1 Opcode 0x3d
vrmmax-current (EDC) MP1 Opcode 0x3d MP1 Opcode 0x3c

Sending inverted opcodes on either platform produces invalid voltage regulator current limits or hardware communication rejection. ZenMaster isolates these families into dedicated socket tables to guarantee correct dispatch.

Rationale for VRMSOC Omission on Desktop MCM Silicon

Monolithic mobile APU socket groups (FT5_FP5_AM4, FP6_AM4, FT6_FP7_FP8) include vrmsoc-current and vrmsocmax-current commands to manage on-die SoC VRM rails feeding integrated graphics and memory controllers.

Desktop AM5 processors (AM5_V1), Dragon Range (AM5_MOBILE), and Fire Range (AM5_FIRERANGE) explicitly omit vrmsoc commands from their command tables. Both Dragon Range (Ryzen 7045HX) and Fire Range (Ryzen 9000HX) are multi-chiplet module (MCM) packages combining desktop client compute chiplets with the desktop 6nm client I/O die (cIOD).

On desktop AM5 architecture, the VDDCR_SOC voltage rail is governed by external motherboard power delivery controllers via serial voltage identification (SVID) rather than autonomous APU current limit registers in the SMU firmware. Dispatching vrmsoc opcodes to desktop chiplet packages causes the SMU coprocessor to reject the transaction with status code 0xFE (SMU_UNKNOWN_CMD) or 0xFF (SMU_FAILED).


Concurrency and Cross-Process Hardware Synchronization

Simultaneous hardware access by monitoring agents, fan controllers, and tuning utilities risks interleaving register writes in PCI configuration space and the SMN aperture. Interleaved writes can corrupt mailbox transactions or latch invalid addresses into the Northbridge address register.

ZenMaster enforces cross-process synchronization using system-level named mutexes (zenmaster/linux.py:25-85, zenmaster/windows.py:19-143):

  • Linux: Acquires an advisory lock on /run/lock/access_pci.lock (with fallback to /tmp/access_pci.lock if /run/lock is inaccessible). Acquisition uses non-blocking fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) in a 5 ms polling loop against a 5000 ms timeout (_PCI_MUTEX_TIMEOUT_MS).
  • Windows: Opens or creates the Win32 named mutex Global\Access_PCI via kernel32.CreateMutexW and waits with kernel32.WaitForSingleObject(handle, 5000). Both WAIT_OBJECT_0 (0x00000000) and WAIT_ABANDONED (0x00000080) are recognized as valid acquisition states, allowing recovery if an external process crashes while holding the lock.
  • macOS: Synchronizes intra-process port access via threading.Lock().

All direct SMN primitives (read_smn, write_smn) and mailbox operations execute inside the pci_mutex_guard() context manager, guaranteeing that register apertures are held exclusively during address-data sequences.


Telemetry and Per-Core Sensor Pipeline

The telemetry subsystem was reorganized in ZenMaster v1.2.0:

  1. zenmaster.sensors replaces legacy table.py. Backward compatibility is preserved by assigning table = sensors and registering sys.modules["zenmaster.table"] = sensors during package initialization (zenmaster/__init__.py:5-7).
  2. read_sensors(data, ver) decodes raw PM table buffers into PmSensors, mapping limits and physical metrics against version-specific struct layouts.
  3. read_core_sensors(data, ver, ccd_count) extracts per-core telemetry matrices:
    • Scales target core count to max(core_count, ccd_count * 8) to account for physical multi-CCD topologies.
    • Decodes architectural telemetry blocks: core power, core voltage, core temperature, physical core clock, effective core clock, and C0/CC1/CC6 residencies.
    • Filters out down-fused cores where physical clocks read zero.
  4. read_pm_core_sensors() provides high-level telemetry acquisition, resolving active CCD counts via get_ccd_count() prior to parsing.

Exception Hierarchy

All custom exceptions derive from ZenMasterError (zenmaster/errors.py):

ZenMasterError(RuntimeError)
  |-- BackendUnavailable    # Underlying driver or transport missing or unauthorized
  |-- SMUNotInitialized     # Attempted SMU operation prior to init() call
  `-- UnsupportedCPU        # CPU family lacks socket or opcode mappings

Backend initialization guards verify interface status prior to mailbox execution. When hardware communication fails or prerequisites are unfulfilled, typed exceptions report actionable diagnostic messages to user space.

Clone this wiki locally