Launch arguments
← POPSLoader docs ยท view on GitHub โ
POPSLoader accepts NHDDL-style launch arguments so a front-end (OSDMenu /
HOSDMenu, wLaunchELF, a forwarder, etc.) can boot it straight to a device
page or auto-launch a specific game. Arguments are parsed in
src/main.cpp parseLaunchArgs(), exposed to Lua via
System.getLaunchArgs(), and acted on in bin/POPSLDR/system.lua.
The arguments
| Argument | Effect |
|---|---|
-page=<device> |
Boot straight into that device's game list (when used without -game). |
-mode=<device> |
NHDDL-compatible alias for -page= (identical behavior, same values). |
-game=<selector> |
Auto-launch a game. Must be combined with -page=. |
-debug |
Show an on-screen toast with the parsed args + resolved boot context. |
Each argument is a separate token, exactly like a command line:
mc0:/PS1_POPSLOADER/POPSLOADER.ELF -page=hdd
mc0:/PS1_POPSLOADER/POPSLOADER.ELF -mode=ata
mc0:/PS1_POPSLOADER/POPSLOADER.ELF -page=usb -game=Tekken 3
mc0:/PS1_POPSLOADER/POPSLOADER.ELF -page=hdd -debug
The first token is always POPSLoader's own ELF path; the launcher supplies
it as argv[0]. Pass each flag as its own argument entry โ do not join
them into one quoted string (see Front-end notes below).
Accepted -page / -mode values
Values are case-insensitive. Aliases in parentheses resolve to the same
page:
| Page | Accepted values |
|---|---|
| HDD (PFS) | hdd, ata, pfs, apa |
| USB | usb, mass |
| MC | mc, memcard (accepted but not navigable โ there is no standalone Memory Card page; standard PS2 memory cards are not a separate carousel device) |
| MMCE | mmce |
| MX4SIO | mx4sio, mx4, sdc |
| SMB | smb |
| BDMA (HDD exFAT) | bdma (accepted but not navigable โ see below) |
-mode=ata is provided specifically for NHDDL parity (-mode=ata is how
NHDDL selects the HDD/ATA path).
What each argument actually does
-page= / -mode= (open a device's game list)
Boots straight into the requested device's game list (the same screen
you'd reach by scrolling to that page and pressing X) โ it loads the
device and switches to its list automatically. Combine with -game= to go
one step further and auto-launch a specific title (see below); -page=
alone just opens the list so you can pick.
Enterable pages: MMCE, MX4SIO, HDD (PFS), USB. The HDD value
targets the implemented PFS page. bdma (HDD exFAT) and the i.Link
page are intentionally not wired, so -page=bdma is accepted but has
no effect. An unrecognized value is ignored and the carousel starts on its
default page (MMCE) with no auto-entry.
-game= (auto-launch)
Boots straight into launching a game. Requires both -page= and
-game=. Auto-launch is wired for these pages:
| Page | -game= selector format |
|---|---|
| HDD | <PARTITION>\|<VCD> โ the POPS partition label, a literal \|, then the .VCD filename (e.g. __.POPS\|SLUS_007.42.RAMPAGE.VCD). A bare title fails with an "Invalid HDD game entry" toast. |
| USB | <FILE> relative to mass:/POPS |
| MX4SIO | <FILE> relative to mx4sio:/POPS |
| MMCE | <FILE> relative to mmce0:/POPS |
If auto-launch fails (game not found, etc.) POPSLoader does not hang โ
it falls back to the normal welcome screen + main menu and shows an error
toast describing what happened. SMB: SMB (v1) is an unimplemented stub.
-page=smb positions the carousel on the SMB page, but auto-entering it
shows a "This backend isn't implemented yet" toast (no list opens).
-page=smb -game=... shows an "Auto-launch page not supported: SMB" toast.
Both leave you on the main menu.
-debug
Queues an on-screen info toast on the first main-menu frame listing:
[debug] boot context
kind: <HDD|USB|MC|MMCE|MX4SIO|SMB|HOST>
boot_path: <argv[0]>
sidecar: <settings sidecar path>
settings: <resolved settings path>
video: req=<n> got=<n> free=<n> <W>x<H>
args.page: <normalized page or <nil>>
args.game: <selector or <nil>>
Use this to confirm the args actually reached POPSLoader. If the toast
shows args.page: HDD you know parsing works and any remaining problem is
downstream; if the toast never appears, the args didn't reach
parseLaunchArgs() at all (front-end delivery or an outdated build).
The video: line is the GS mode readback (requested vs. obtained mode,
free VRAM, and resolution; NTSC=2/PAL=3). It is omitted only if
UI.VIDEO_READBACK was not captured (e.g. the boot video-mode apply was
short-circuited).
Front-end notes (important)
- One flag per argument entry. Front-ends that pass each argument as a
distinctargvtoken (OSDMenu'sarg_OSDSYS_ITEM_<n>lines, NHDDL,
OPL) work directly. Writing two flags on one line โ e.g.
-page=hdd -debugas a single value โ historically arrived as one token
"-page=hdd -debug". POPSLoader now defends against this (it keeps only
the first word of a page value and still detects a trailing-debug),
but the clean, portable form is two separate argument entries. - Whitespace / quotes are tolerated. Leading/trailing spaces and one
pair of surrounding quotes are stripped from each token (some CNF parsers
leave a trailing space on the line). Internal spaces in-game=values
are preserved (USB/MX4SIO/MMCE.VCDfilenames may contain spaces; the
HDD selector is the<PARTITION>|<VCD>form, not a bare title). - OSDMenu Browser-icon (PATINFO) launches don't read
arg_OSDSYS_ITEM_*; for those, arguments come from the OSDMenu
SYSTEM.CNFargextensions in the partition attribute area. - Build requirement. These arguments shipped in BETA-12 (feature
added 2026-05-25 on theBETA-12-PLAYdev branch). Builds older than
BETA-12 do not have them. All Lua runs from assets
embedded in the ELF at build time, so updating on-card.luafiles has
no effect โ you must run a currentPOPSLOADER.ELF. Verify with
-debug.
Example OSDMenu OSDMENU.CNF entry
name_OSDSYS_ITEM_1 = POPSLoader (HDD)
path1_OSDSYS_ITEM_1 = mc0:/PS1_POPSLOADER/POPSLOADER.ELF
arg_OSDSYS_ITEM_1 = -page=hdd
Add games or debug as additional, separate arg_OSDSYS_ITEM_1 lines:
arg_OSDSYS_ITEM_1 = -page=hdd
arg_OSDSYS_ITEM_1 = -game=__.POPS|SLUS_007.42.RAMPAGE.VCD
arg_OSDSYS_ITEM_1 = -debug
Source map (for maintainers)
| Concern | Location |
|---|---|
| Token parse + trim | src/main.cpp parseLaunchArgs(), trimLaunchArgToken() |
| Lua binding | src/luasystem.cpp lua_getLaunchArgs() โ System.getLaunchArgs() |
| Normalize + populate | bin/POPSLDR/system.lua NormalizeLaunchPage() + PLDR.LAUNCH_ARGS |
| Carousel navigation | bin/POPSLDR/system.lua page-jump block (raises Carousel.allowOptWrite) |
| Auto-launch | bin/POPSLDR/system.lua PLDR.AutoLaunchFromLaunchArgs() |
| Debug toast | bin/POPSLDR/system.lua PLDR.SurfaceLaunchArgsDebug() |
Why navigation needs allowOptWrite
UI.MainMenu installs a __newindex write-guard that silently drops any
OPT assignment unless Carousel.allowOptWrite is raised, and
MainMenu.Play() re-syncs the carousel from OPT every non-animating
frame. The page-jump block therefore raises that gate around its OPT
write (and sets the carousel indices to match). Without it the navigation
is a silent no-op โ that was the 2026-06 "launch args do nothing on
hardware" bug.