-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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. |
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.
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).
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 |
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 |
Every detected processor is classified into one of four categories (zenmaster/hardware.py:298-304):
-
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), andOlympicRidgealongsideDhyana. -
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). -
Intel: Applied whenever the processor vendor string contains"Intel". The ZenMaster CLI explicitly rejects non-AMD hardware. -
Unknown: Fallback category for unrecognized architectures.
ZenMaster executes unprivileged CPUID and model resolution across operating systems:
-
Linux (
_parse_cpuinfo): Parses/proc/cpuinfoto extractcpu family,model,stepping, andmodel name. -
Windows (
_parse_processor_identifier): Extracts numeric values from thePROCESSOR_IDENTIFIERenvironment string (for example,"AMD64 Family 25 Model 97 Stepping 2"), followed by querying the branding string from registry keyHKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\ProcessorNameString. -
macOS (
_parse_sysctl): Directlibcinvocation ofsysctlbynameagainstmachdep.cpu.family,machdep.cpu.model,machdep.cpu.stepping, andmachdep.cpu.brand_string. CPUID values retrieved viasysctlbynamebypass SMBIOS modifications injected by bootloaders.
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- Default mapping (Matisse, Zen 3, Zen 4, Zen 5, Zen 6):
0x0005D218(ccd_fuse1) and0x0005D21C(ccd_fuse2). - Zen 1 / Zen+ non-Matisse offset (
family_int == 23 and model_int != 113): A+0x40register offset is applied, targeting0x0005D258and0x0005D25C.
-
presentreads the physical CCD availability bitmap fromccd_fuse1. -
downreads the down-fused disabled CCD bitmap fromccd_fuse2. -
disabled = ((down & 0x3F) << 2) | ((present >> 30) & 0x3)extracts down-fused dies across both registers. -
enabled = ((present >> 22) & 0xFF) & ~disabledmasks active dies against disabled bit positions. -
count = enabled.bit_count()counts the active set bits, falling back to 1 if the calculation evaluates to 0 or triggers anOSError.
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.
ZenMaster maps CPU families into 10 distinct socket dispatch tables (zenmaster/runner.py:3-61):
-
SOCKET_AM4_V1: Summit Ridge, Pinnacle Ridge, Threadripper 1000/2000, Naples, Colfax, Dhyana. -
SOCKET_FT5_FP5_AM4: Raven Ridge, Raven Ridge 2, Picasso, Dali, Pollock, FireFlight. -
SOCKET_AM4_V2: Rome, Castle Peak, Matisse, Milan, Chagall, Vermeer. -
SOCKET_FP6_AM4: Renoir, Lucienne, Cezanne / Barcelo. -
SOCKET_FF3: VanGogh (Steam Deck custom APU). -
SOCKET_FT6_FP7_FP8: Mendocino, Rembrandt, Phoenix Point, Hawk Point, Sonoma Valley, Strix Point, Krackan Point, Strix Halo. -
SOCKET_AM5_V1: Raphael, Storm Peak, Genoa, Bergamo, Siena, Turin, Turin Dense, Granite Ridge. -
SOCKET_AM5_MOBILE: Dragon Range (Ryzen 7045HX series). -
SOCKET_AM5_FIRERANGE: Fire Range (Ryzen 9000HX series). -
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.
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.
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).
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.lockif/run/lockis inaccessible). Acquisition uses non-blockingfcntl.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_PCIviakernel32.CreateMutexWand waits withkernel32.WaitForSingleObject(handle, 5000). BothWAIT_OBJECT_0(0x00000000) andWAIT_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.
The telemetry subsystem was reorganized in ZenMaster v1.2.0:
-
zenmaster.sensorsreplaces legacytable.py. Backward compatibility is preserved by assigningtable = sensorsand registeringsys.modules["zenmaster.table"] = sensorsduring package initialization (zenmaster/__init__.py:5-7). -
read_sensors(data, ver)decodes raw PM table buffers intoPmSensors, mapping limits and physical metrics against version-specific struct layouts. -
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.
- Scales target core count to
-
read_pm_core_sensors()provides high-level telemetry acquisition, resolving active CCD counts viaget_ccd_count()prior to parsing.
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.
PyPI | Report an Issue | Releases | Under GPL-3.0 by HorizonUnix
Getting started
Monitoring
Developers
Help