diff --git a/site/.nojekyll b/site/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/site/css/style.css b/site/css/style.css new file mode 100644 index 0000000..252ac0d --- /dev/null +++ b/site/css/style.css @@ -0,0 +1,992 @@ +/* ============================================ + rust-psp GitHub Pages — PSP XMB-inspired theme + ============================================ */ + +/* --- Reset & Base --- */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --bg-deep: #0a0a0f; + --bg-card: #12121a; + --bg-code: #1a1a2e; + --bg-hover: #1a1a28; + --accent-blue: #4a9eff; + --accent-purple: #7c5cff; + --accent-cyan: #00d4aa; + --text-primary: #e8e8f0; + --text-muted: #8888aa; + --text-dim: #555570; + --border-color: #2a2a3e; + --nav-height: 60px; + --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Source Code Pro', monospace; + --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; + --max-width: 1200px; + --section-padding: 100px 0; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: var(--nav-height); +} + +body { + font-family: var(--font-body); + background: var(--bg-deep); + color: var(--text-primary); + line-height: 1.6; + overflow-x: hidden; + -webkit-font-smoothing: antialiased; +} + +a { + color: var(--accent-blue); + text-decoration: none; + transition: color 0.2s; +} + +a:hover { + color: var(--accent-cyan); +} + +img { + max-width: 100%; +} + +/* --- Container --- */ +.container { + max-width: var(--max-width); + margin: 0 auto; + padding: 0 24px; +} + +/* --- Navigation --- */ +.nav { + position: fixed; + top: 0; + left: 0; + right: 0; + height: var(--nav-height); + z-index: 1000; + transition: background 0.3s, box-shadow 0.3s; + background: transparent; +} + +.nav.scrolled { + background: rgba(10, 10, 15, 0.95); + box-shadow: 0 1px 20px rgba(0, 0, 0, 0.5); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); +} + +.nav-inner { + max-width: var(--max-width); + margin: 0 auto; + padding: 0 24px; + height: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} + +.nav-logo { + font-family: var(--font-mono); + font-size: 1.2rem; + font-weight: 700; + color: var(--text-primary); + display: flex; + align-items: center; + gap: 8px; +} + +.nav-logo .accent { + color: var(--accent-blue); +} + +.nav-links { + display: flex; + gap: 8px; + list-style: none; +} + +.nav-links a { + color: var(--text-muted); + font-size: 0.875rem; + padding: 6px 12px; + border-radius: 6px; + transition: color 0.2s, background 0.2s; +} + +.nav-links a:hover, +.nav-links a.active { + color: var(--text-primary); + background: rgba(74, 158, 255, 0.1); +} + +.nav-github { + display: flex; + align-items: center; + gap: 6px; + color: var(--text-muted); + font-size: 0.875rem; + padding: 6px 14px; + border: 1px solid var(--border-color); + border-radius: 8px; + transition: all 0.2s; +} + +.nav-github:hover { + color: var(--text-primary); + border-color: var(--accent-blue); + background: rgba(74, 158, 255, 0.08); +} + +.nav-github svg { + width: 18px; + height: 18px; + fill: currentColor; +} + +/* Hamburger */ +.hamburger { + display: none; + flex-direction: column; + gap: 5px; + background: none; + border: none; + cursor: pointer; + padding: 4px; +} + +.hamburger span { + display: block; + width: 24px; + height: 2px; + background: var(--text-muted); + transition: transform 0.3s, opacity 0.3s; +} + +.hamburger.open span:nth-child(1) { + transform: rotate(45deg) translate(5px, 5px); +} + +.hamburger.open span:nth-child(2) { + opacity: 0; +} + +.hamburger.open span:nth-child(3) { + transform: rotate(-45deg) translate(5px, -5px); +} + +/* Mobile nav overlay (hidden by default, shown via JS on small screens) */ +.nav-mobile { + display: none; +} + +/* --- Hero --- */ +.hero { + position: relative; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + padding: 120px 24px 80px; + overflow: hidden; +} + +.hero-bg { + position: absolute; + inset: 0; + background: + radial-gradient(ellipse 80% 60% at 50% 40%, rgba(74, 158, 255, 0.12) 0%, transparent 60%), + radial-gradient(ellipse 60% 50% at 30% 60%, rgba(124, 92, 255, 0.08) 0%, transparent 50%), + radial-gradient(ellipse 50% 40% at 70% 70%, rgba(0, 212, 170, 0.05) 0%, transparent 50%); + animation: heroShift 12s ease-in-out infinite alternate; +} + +@keyframes heroShift { + 0% { transform: scale(1) translate(0, 0); } + 50% { transform: scale(1.05) translate(-1%, 2%); } + 100% { transform: scale(1) translate(1%, -1%); } +} + +.hero-waves { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 200px; + overflow: hidden; +} + +.hero-waves svg { + position: absolute; + bottom: 0; + width: 200%; + height: 100%; +} + +.wave-1 { animation: waveDrift 8s ease-in-out infinite; opacity: 0.15; } +.wave-2 { animation: waveDrift 12s ease-in-out infinite reverse; opacity: 0.1; } + +@keyframes waveDrift { + 0%, 100% { transform: translateX(0); } + 50% { transform: translateX(-25%); } +} + +.hero-content { + position: relative; + z-index: 1; +} + +.hero h1 { + font-family: var(--font-mono); + font-size: clamp(3rem, 8vw, 5rem); + font-weight: 800; + letter-spacing: -2px; + margin-bottom: 16px; + background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple), var(--accent-cyan)); + background-size: 200% 200%; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: gradientText 6s ease-in-out infinite; +} + +@keyframes gradientText { + 0%, 100% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } +} + +.hero-tagline { + font-size: clamp(1.1rem, 2.5vw, 1.5rem); + color: var(--text-primary); + margin-bottom: 8px; + font-weight: 300; +} + +.hero-subtitle { + font-family: var(--font-mono); + font-size: 0.9rem; + color: var(--text-muted); + margin-bottom: 32px; +} + +.hero-stats { + display: flex; + justify-content: center; + gap: 16px; + margin-bottom: 40px; + flex-wrap: wrap; +} + +.stat-badge { + font-family: var(--font-mono); + font-size: 0.85rem; + padding: 8px 20px; + border-radius: 100px; + border: 1px solid var(--border-color); + background: rgba(18, 18, 26, 0.8); + color: var(--text-primary); +} + +.stat-badge .num { + color: var(--accent-cyan); + font-weight: 700; +} + +.hero-buttons { + display: flex; + justify-content: center; + gap: 16px; + flex-wrap: wrap; +} + +.btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 12px 28px; + border-radius: 10px; + font-size: 0.95rem; + font-weight: 600; + transition: all 0.25s; + cursor: pointer; + border: none; +} + +.btn-primary { + background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); + color: #fff; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(74, 158, 255, 0.3); + color: #fff; +} + +.btn-outline { + background: transparent; + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +.btn-outline:hover { + border-color: var(--accent-blue); + background: rgba(74, 158, 255, 0.08); + color: var(--text-primary); + transform: translateY(-2px); +} + +/* --- Sections --- */ +section { + padding: var(--section-padding); +} + +.section-header { + text-align: center; + margin-bottom: 60px; +} + +.section-header h2 { + font-family: var(--font-mono); + font-size: clamp(1.8rem, 4vw, 2.5rem); + font-weight: 700; + margin-bottom: 12px; +} + +.section-header h2 .accent { + color: var(--accent-blue); +} + +.section-header p { + color: var(--text-muted); + font-size: 1.05rem; + max-width: 600px; + margin: 0 auto; +} + +/* --- Scroll Animations --- */ +.fade-in { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.6s ease-out, transform 0.6s ease-out; +} + +.fade-in.visible { + opacity: 1; + transform: translateY(0); +} + +/* --- Features Grid --- */ +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); + gap: 24px; +} + +.feature-card { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 16px; + padding: 32px; + transition: transform 0.25s, border-color 0.25s, box-shadow 0.25s; +} + +.feature-card:hover { + transform: translateY(-4px); + border-color: var(--accent-blue); + box-shadow: 0 8px 40px rgba(74, 158, 255, 0.08); +} + +.feature-icon { + font-size: 2rem; + margin-bottom: 16px; + display: block; + width: 48px; + height: 48px; + line-height: 48px; + text-align: center; + border-radius: 12px; + background: rgba(74, 158, 255, 0.1); +} + +.feature-card h3 { + font-family: var(--font-mono); + font-size: 1.05rem; + margin-bottom: 8px; +} + +.feature-card p { + color: var(--text-muted); + font-size: 0.9rem; + line-height: 1.5; +} + +/* --- Quick Start --- */ +.quickstart-steps { + max-width: 800px; + margin: 0 auto; +} + +.step { + margin-bottom: 40px; +} + +.step-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 12px; +} + +.step-num { + font-family: var(--font-mono); + font-size: 0.8rem; + font-weight: 700; + width: 28px; + height: 28px; + line-height: 28px; + text-align: center; + border-radius: 8px; + background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); + color: #fff; + flex-shrink: 0; +} + +.step h3 { + font-size: 1.05rem; +} + +.step p { + color: var(--text-muted); + font-size: 0.9rem; + margin-bottom: 12px; + padding-left: 40px; +} + +/* --- Code Blocks --- */ +pre { + background: var(--bg-code); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: 20px 24px; + overflow-x: auto; + font-family: var(--font-mono); + font-size: 0.85rem; + line-height: 1.7; + margin-left: 40px; + position: relative; +} + +pre .lang-label { + position: absolute; + top: 8px; + right: 12px; + font-size: 0.7rem; + color: var(--text-dim); + text-transform: uppercase; + letter-spacing: 1px; +} + +code { + font-family: var(--font-mono); +} + +/* Inline code */ +p code, li code, td code { + background: var(--bg-code); + padding: 2px 6px; + border-radius: 4px; + font-size: 0.85em; + color: var(--accent-cyan); +} + +/* Syntax highlighting */ +.kw { color: #c792ea; } /* keywords */ +.fn { color: #82aaff; } /* functions */ +.str { color: #c3e88d; } /* strings */ +.cm { color: #546e7a; } /* comments */ +.ty { color: #ffcb6b; } /* types */ +.mac { color: #89ddff; } /* macros */ +.num { color: #f78c6c; } /* numbers */ +.at { color: #ff5572; } /* attributes */ +.lf { color: #f07178; } /* lifetime */ + +/* --- Modules --- */ +.modules-section { + background: + linear-gradient(180deg, var(--bg-deep) 0%, rgba(18, 18, 26, 0.5) 50%, var(--bg-deep) 100%); +} + +.module-categories { + max-width: 900px; + margin: 0 auto; +} + +.module-category { + border: 1px solid var(--border-color); + border-radius: 12px; + margin-bottom: 12px; + overflow: hidden; + background: var(--bg-card); +} + +.module-category-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 24px; + cursor: pointer; + transition: background 0.2s; + user-select: none; +} + +.module-category-header:hover { + background: var(--bg-hover); +} + +.module-category-header h3 { + font-family: var(--font-mono); + font-size: 0.95rem; + display: flex; + align-items: center; + gap: 10px; +} + +.module-count { + font-size: 0.75rem; + color: var(--text-dim); + background: rgba(74, 158, 255, 0.1); + padding: 2px 8px; + border-radius: 100px; +} + +.module-chevron { + font-size: 0.8rem; + color: var(--text-dim); + transition: transform 0.3s; +} + +.module-category.open .module-chevron { + transform: rotate(180deg); +} + +.module-list { + display: none; + padding: 0 24px 16px; +} + +.module-category.open .module-list { + display: block; +} + +.module-item { + display: flex; + align-items: baseline; + gap: 12px; + padding: 8px 0; + border-top: 1px solid rgba(42, 42, 62, 0.5); +} + +.module-name { + font-family: var(--font-mono); + font-size: 0.85rem; + color: var(--accent-blue); + white-space: nowrap; + min-width: 120px; +} + +.module-desc { + color: var(--text-muted); + font-size: 0.85rem; +} + +.module-types { + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-dim); + margin-top: 2px; +} + +/* --- Examples Gallery --- */ +.filter-bar { + display: flex; + justify-content: center; + gap: 8px; + margin-bottom: 40px; + flex-wrap: wrap; +} + +.filter-btn { + font-family: var(--font-mono); + font-size: 0.8rem; + padding: 6px 16px; + border-radius: 100px; + border: 1px solid var(--border-color); + background: transparent; + color: var(--text-muted); + cursor: pointer; + transition: all 0.2s; +} + +.filter-btn:hover { + border-color: var(--accent-blue); + color: var(--text-primary); +} + +.filter-btn.active { + background: rgba(74, 158, 255, 0.15); + border-color: var(--accent-blue); + color: var(--accent-blue); +} + +.examples-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 16px; +} + +.example-card { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: 20px; + transition: transform 0.2s, border-color 0.2s; + display: flex; + flex-direction: column; +} + +.example-card:hover { + transform: translateY(-2px); + border-color: var(--accent-purple); +} + +.example-card.hidden { + display: none; +} + +.example-card h4 { + font-family: var(--font-mono); + font-size: 0.9rem; + margin-bottom: 6px; +} + +.example-tags { + display: flex; + gap: 6px; + margin-bottom: 8px; + flex-wrap: wrap; +} + +.example-tag { + font-family: var(--font-mono); + font-size: 0.65rem; + padding: 2px 8px; + border-radius: 4px; + background: rgba(124, 92, 255, 0.12); + color: var(--accent-purple); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.example-card p { + color: var(--text-muted); + font-size: 0.82rem; + line-height: 1.45; + flex: 1; +} + +.example-card .view-source { + display: inline-flex; + align-items: center; + gap: 4px; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--accent-blue); + margin-top: 12px; +} + +.example-card .view-source:hover { + color: var(--accent-cyan); +} + +/* --- Architecture --- */ +.arch-diagram { + max-width: 800px; + margin: 0 auto; +} + +.arch-block { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 16px; + padding: 32px; + margin-bottom: 32px; +} + +.arch-block h3 { + font-family: var(--font-mono); + font-size: 1rem; + margin-bottom: 20px; + color: var(--accent-blue); +} + +.arch-flow { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 8px; + font-family: var(--font-mono); + font-size: 0.82rem; +} + +.arch-node { + padding: 10px 16px; + border: 1px solid var(--border-color); + border-radius: 8px; + background: var(--bg-code); + text-align: center; + white-space: nowrap; +} + +.arch-arrow { + color: var(--text-dim); + font-size: 1.1rem; +} + +.arch-layers { + display: flex; + flex-direction: column; + gap: 8px; +} + +.arch-layer { + display: flex; + align-items: center; + gap: 12px; + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.arch-layer-bar { + flex: 1; + padding: 12px 16px; + border-radius: 8px; + text-align: center; +} + +.arch-layer-bar.l4 { + background: rgba(74, 158, 255, 0.15); + border: 1px solid rgba(74, 158, 255, 0.3); + color: var(--accent-blue); +} + +.arch-layer-bar.l3 { + background: rgba(124, 92, 255, 0.12); + border: 1px solid rgba(124, 92, 255, 0.25); + color: var(--accent-purple); +} + +.arch-layer-bar.l2 { + background: rgba(0, 212, 170, 0.1); + border: 1px solid rgba(0, 212, 170, 0.2); + color: var(--accent-cyan); +} + +.arch-layer-bar.l1 { + background: rgba(136, 136, 170, 0.08); + border: 1px solid rgba(136, 136, 170, 0.15); + color: var(--text-muted); +} + +/* --- Tools --- */ +.tools-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); + gap: 24px; + max-width: 900px; + margin: 0 auto 40px; +} + +.tool-card { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 16px; + padding: 28px; +} + +.tool-card h3 { + font-family: var(--font-mono); + font-size: 1rem; + margin-bottom: 8px; + color: var(--accent-cyan); +} + +.tool-card p { + color: var(--text-muted); + font-size: 0.88rem; + line-height: 1.5; +} + +.config-example { + max-width: 700px; + margin: 0 auto; +} + +.config-example h3 { + font-family: var(--font-mono); + font-size: 1rem; + margin-bottom: 12px; + text-align: center; +} + +.config-example pre { + margin-left: 0; +} + +/* --- Footer --- */ +.footer { + border-top: 1px solid var(--border-color); + padding: 48px 0; + text-align: center; +} + +.footer-links { + display: flex; + justify-content: center; + gap: 24px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.footer-links a { + color: var(--text-muted); + font-size: 0.85rem; +} + +.footer-links a:hover { + color: var(--accent-blue); +} + +.footer-meta { + color: var(--text-dim); + font-size: 0.8rem; + line-height: 1.8; +} + +.footer-meta .version { + font-family: var(--font-mono); + display: inline-block; + padding: 2px 10px; + border-radius: 4px; + background: rgba(74, 158, 255, 0.1); + color: var(--accent-blue); + font-size: 0.75rem; +} + +/* --- Responsive --- */ +@media (max-width: 768px) { + :root { + --section-padding: 60px 0; + --nav-height: 56px; + } + + .nav-links, + .nav-github-desktop { + display: none; + } + + .hamburger { + display: flex; + } + + .nav-mobile { + display: none; + position: fixed; + top: var(--nav-height); + left: 0; + right: 0; + bottom: 0; + background: rgba(10, 10, 15, 0.98); + backdrop-filter: blur(12px); + z-index: 999; + padding: 24px; + } + + .nav-mobile.open { + display: flex; + flex-direction: column; + gap: 4px; + } + + .nav-mobile a { + color: var(--text-muted); + font-size: 1.1rem; + padding: 14px 16px; + border-radius: 8px; + display: block; + transition: background 0.2s, color 0.2s; + } + + .nav-mobile a:hover, + .nav-mobile a.active { + background: rgba(74, 158, 255, 0.1); + color: var(--text-primary); + } + + .features-grid { + grid-template-columns: 1fr; + } + + .examples-grid { + grid-template-columns: 1fr; + } + + .tools-grid { + grid-template-columns: 1fr; + } + + pre { + margin-left: 0; + font-size: 0.8rem; + padding: 16px; + } + + .step p { + padding-left: 0; + } + + .arch-flow { + flex-direction: column; + } + + .hero-stats { + flex-direction: column; + align-items: center; + } +} + +@media (max-width: 480px) { + .hero h1 { + letter-spacing: -1px; + } + + .section-header { + margin-bottom: 40px; + } + + .feature-card { + padding: 24px; + } + + .module-category-header { + padding: 14px 16px; + } +} diff --git a/site/img/favicon.svg b/site/img/favicon.svg new file mode 100644 index 0000000..7f0bbde --- /dev/null +++ b/site/img/favicon.svg @@ -0,0 +1,16 @@ + diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..e7242f7 --- /dev/null +++ b/site/index.html @@ -0,0 +1,915 @@ + + +
+ + +A Modern Rust SDK for Sony PSP Homebrew Development
+Edition 2024 · Safety Hardened · Kernel Mode Support
+ +Everything you need to write modern, safe homebrew for the PSP.
+829 bindings across 33 modules covering every PSP subsystem — graphics, audio, networking, I/O, threading, and more.
+33 high-level modules with RAII resource management, Result types, and zero panics in allocators or VRAM code.
+Privileged APIs for NAND flash, IR remote, ME coprocessor, syscall hooking, and hardware register I/O.
+cargo-psp wraps the entire pipeline: Rust source to ELF to PRX to EBOOT.PBP with a single command.
+Use String, Vec, HashMap, and the full Rust standard library on PSP for familiar, productive development.
+Automated integration tests run in PPSSPPHeadless via Docker, ensuring code works on real PSP hardware.
+Get from zero to running PSP homebrew in minutes.
+You'll need Rust nightly and the source component for cross-compilation.
+bash +rustup default nightly +rustup component add rust-src+
Download a prebuilt binary from Releases, or build from source.
+bash +# From crates.io (or GitHub Releases for prebuilt binaries) +cargo install cargo-psp+
Set up a new Cargo project and write your first PSP module.
+bash +cargo new hello-psp && cd hello-psp+
Add psp to your Cargo.toml, then write your entry point:
rust +#![no_std] +#![no_main] + +use psp; + +psp::module!("hello_psp", 1, 1); + +fn psp_main() { + psp::dprintln!("Hello from the PSP!"); +}+
Build your project into an EBOOT.PBP that the PSP can run.
+bash +cargo +nightly psp --release +# Output: target/mipsel-sony-psp/release/EBOOT.PBP+
Copy the EBOOT.PBP to your PSP's ms0:/PSP/GAME/hello_psp/ folder, or open it in PPSSPP.
33 high-level modules organized by domain. Click a category to explore.
+30 working examples covering graphics, audio, networking, input, and more.
+Generates and plays a 440Hz sine wave tone for 3 seconds using the PSP audio subsystem.
+ View Source → +Saves and loads key-value configuration settings with multiple data types to binary RCFG format.
+ View Source → +Renders a rotating 3D textured cube using the GU graphics engine with matrix transforms and depth testing.
+ View Source → +Draws shapes and text using the embedded-graphics library including triangles, rectangles, and circles.
+ View Source → +Demonstrates basic file I/O operations writing and reading text files to the host filesystem.
+ View Source → +Renders scrolling text with fontdue library using sine wave animation and VRAM sprite batching.
+ View Source → +Basic GU graphics initialization and display setup showing a colored background.
+ View Source → +Uses GU debug print functionality to render text directly to the graphics display.
+ View Source → +Minimal example that prints a hello message to the debug output.
+ View Source → +High-level HTTP GET requests via psp::http::HttpClient with WiFi connectivity.
+ View Source → +Reads analog stick input with deadzone normalization and button press detection.
+ View Source → +Demonstrates kernel-mode privileged APIs including ME clock, volatile memory, NAND flash, and hardware registers.
+ View Source → +Displays a message dialog box using the GU-rendered system dialog utility.
+ View Source → +Connects via WiFi and performs HTTP GET requests using raw TCP sockets.
+ View Source → +Text input via on-screen keyboard (OSK) utility with both convenience function and builder pattern.
+ View Source → +Simple drawing application with analog stick control and button-based tool selection.
+ View Source → +Animated rainbow color transitions filling the screen via direct framebuffer manipulation.
+ View Source → +Terminal UI rendering using ratatui library with styled text, borders, and layout widgets.
+ View Source → +Reads RTC date/time with arithmetic and queries system parameters like language and timezone.
+ View Source → +Uses Rust standard library with String, Vec, and format! macros in no_std PSP environment.
+ View Source → +Saves and loads game data with metadata using the PSP savedata utility with GU rendering.
+ View Source → +Renders system fonts with glyph atlas caching using PSP FontLib and FontRenderer API.
+ View Source → +Spawns multiple threads sharing a SpinMutex counter with thread synchronization and join.
+ View Source → +Reads and displays the current date and time from the PSP real-time clock.
+ View Source → +Sets one-shot alarm callbacks and virtual timers with microsecond precision time measurement.
+ View Source → +Performs integer addition using VFPU (Vector FPU) inline assembly with float conversion.
+ View Source → +Demonstrates VFPU context save/restore with matrix operations preserving register state.
+ View Source → +Queries WLAN chip status including power state, switch state, and MAC address.
+ View Source → +How rust-psp is structured and how your code becomes a PSP executable.
+
+ PSP executables require specific ELF sections: .rodata.sceModuleInfo for module metadata,
+ .lib.stub for import stubs, and .lib.ent for exports. The psp_extern!
+ macro generates syscall stubs with NIDs (Numeric IDs) — the first 4 bytes of SHA-1(function_name)
+ in little-endian — which the PSP OS resolves at load time. Module flags 0x0000 for user-mode,
+ 0x1000 for kernel-mode.
+
The cargo-psp suite handles every step from Rust source to PSP executable.
+The main build command. Wraps cargo build, invokes prxgen and pack-pbp automatically, and reads project metadata from Psp.toml. Supports --release, --features, and custom target directories.
Converts a MIPS ELF binary into PSP's PRX (relocatable module) format. Processes import/export tables and fixes up relocations for the PSP loader.
+Creates PBP archives — the PSP's executable package format. Bundles the PRX with SFO metadata, optional icons (ICON0.PNG), backgrounds, and startup sounds.
+Generates SFO (System File Object) metadata files containing the game title, disc ID, firmware version requirements, and parental control level.
+Minimizes PRX files by stripping debug sections and unnecessary ELF data, reducing the final binary size for distribution.
+toml +# Project metadata for pack-pbp +[metadata] +title = "My PSP Game" +disc_id = "RUST00001" +disc_version = "1.00" +firmware_version = "6.60" + +# Optional assets +icon0 = "assets/icon.png" +pic1 = "assets/background.png" + +# Localized titles +[metadata.titles] +japanese = "PSPゲーム" +english = "My PSP Game"+