libdragon SDK

repository·trunk·Indexed 22 days ago

https://github.com/dragonminded/libdragon

An open-source SDK for the Nintendo 64 providing a modern C11 programming and debugging experience. It features advanced 2D/3D graphics, RSP-accelerated audio, high-performance data compression, and the Libdragon IPL3 bootcode for ELF loading and hardware initialization. The SDK offers stable and preview branches, with the latter including experimental features like OpenGL 1.1 port, Tiny3D, and MPEG1 playback.

Tokens
3.7K
Snippets
5
Records
17
Agent score
78%

What's inside libdragon

  1. What is Libdragon IPL3?

    trunk

    Libdragon IPL3 is an open-source bootcode required in each ROM to perform final hardware initializations (specifically RDRAM initialization and configuration) and load/run the main binary.

    Key features include:

    • ELF Loading: Searches for and loads an ELF file appended to the IPL3. Supports both 32-bit and 64-bit ELFs.
    • Compression Support: Supports compressed ELFs where the ELF provides its own decompression function.
    • High Performance: Boots large ELFs significantly faster than Nintendo's original IPL3.
    • Flexibility: Supports ROMs of any size (even < 1 MiB) and does not require a header checksum.
    • Reliability: Clears RDRAM before booting to ensure consistent behavior between emulators and real hardware.
    • Entropy: Collects entropy during boot, providing a 32-bit random integer to the application.
    • Development Mode: A version (ipl3_dev.z64) exists with a pre-signed trampoline (no need to sign every change) and a debugging library for USB/emulator logging.
    • Compatibility: Works on iQue consoles and offers a compat build for legacy build systems.
  2. What is FreeType Amalgamation?

    trunk

    FreeType Amalgamation is a distribution of the FreeType software font engine where the header and source files have been concatenated into one or more very large files.

    Benefits:

    • Ease of Integration: You can add the files directly to your project as source files instead of managing external library linking.
    • Simplified Redistribution: It is easier to redistribute in open-source applications as it eliminates external dependencies.
  3. Understand the difference between libdragon stable and preview branches

    trunk

    Libdragon maintains two distinct development tracks:

    Stable (trunk branch)

    • Goal: Backward compatibility. Changes in the stable branch are designed not to break existing applications.
    • Use case: Production-ready development where API stability is critical.

    Preview (preview branch)

    • Goal: Rapid feature development and testing.
    • Features: Includes experimental features like 3D graphics (OpenGL 1.1 port, Tiny3D), MPEG1 movie playback, rdpq_text engine, and initial multithreading support.
    • Risk: APIs in the preview branch can break at any time. Use this branch if you need cutting-edge features and are prepared to update your code to match API changes.
  4. Run libdragon ROMs using emulators

    trunk

    Libdragon utilizes advanced hardware features that require high-fidelity emulation.

    • Recommended Emulator: Ares is currently the only emulator that accurately emulates the hardware required for libdragon.
    • Hardware Requirements: Ares requires a modern PC with a discrete GPU that supports Vulkan.
    • Developer Tip: Enable "Homebrew mode" in Ares settings to activate developer-specific checks that improve the debugging experience.
  5. How to pack rectangles using rect_pack

    trunk

    The rect_pack library is a C++17 tool for packing rectangles into one or more sprite sheets or atlases. To use it, you provide a Settings object defining your constraints and a list of Size objects representing the rectangles you want to pack. The pack function returns a std::vector<Sheet>, where each Sheet contains the dimensions and the list of Rect objects (with their x, y, width, height, and rotated status) that fit within it.

    Note on IDs: The id field in the input Size struct is used to correlate input rectangles with their output positions in the Rect struct. If a rectangle does not fit within the provided constraints, it will not appear in any returned Sheet.

    #include <vector>
    #include "rect_pack.h"
    
    // Example usage concept:
    rect_pack::Settings settings = { /* ... initialize settings ... */ };
    std::vector<rect_pack::Size> sizes = { {1, 32, 32}, {2, 64, 64} };
    
    std::vector<rect_pack::Sheet> sheets = rect_pack::pack(settings, sizes);
    
    for (const auto& sheet : sheets) {
        for (const auto& rect : sheet.rects) {
            // Use rect.id to match back to the original size
            // rect.x, rect.y, rect.width, rect.height, rect.rotated
        }
    }
  6. Install the libdragon toolchain

    trunk

    To begin developing for the Nintendo 64 with libdragon, you must first download and install the specialized GCC toolchain.

    1. Download the toolchain from the official releases page.
    2. Follow the detailed system requirements and installation steps in the official installation guide.
    # Download and install the toolchain from:
    # https://github.com/DragonMinded/libdragon/releases/tag/toolchain-continuous-prerelease
  7. How to use standard Libdragon IPL3

    trunk

    By default, Libdragon uses this IPL3 via the n64tool application embedded in n64.mk. Standard libdragon applications will use it automatically.

    If you are using your own programming environment, follow these requirements:

    ELF Requirements

    • Format: Provide a statically-linked ELF file.
    • Alignment: The ELF file must be concatenated to the IPL3 .z64 file and must be 256-byte aligned. You can add other data before/after as long as the ELF remains 256-byte aligned.
    • Segments:
      • All PT_LOAD segments will be loaded.
      • Virtual addresses must be 8-byte aligned.
      • File offsets must be 2-byte aligned.
      • Constraint: Do not load segments into the last 64 KiB of RDRAM, as this is reserved for IPL3.
    • Header: IPL3 ignores the 64-byte ROM header.

    Boot Flags (passed in DMEM)

    IPL3 passes boot flags to your application at the beginning of DMEM. The layout is:

    • Byte 0..3: Amount of memory (in bytes).
    • Byte 4..7: 32-bit random number (entropy).
    • Byte 8: ROM type (0: Cartridge at 0x10000000, 1: 64DD IPL at 0x06000000).
    • Byte 9: TV type (0: PAL, 1: NTSC, 2: MPAL).
    • Byte 10: Reset type (0: cold, 1: warm).
    • Byte 11: Console type (0: n64, 1: iQue).
    • Byte 12..13: Offset of the ELF header in ROM (in 256-byte pages; multiply by 256 for byte offset).
    • Byte 14..15: Reserved.

    Register State

    • $sp (Stack Pointer) points to the end of the available RDRAM.
  8. Build Libdragon IPL3

    trunk

    Pre-built binaries are available in the bin directory. You can build them from source using the provided Makefile.

    Build Development Version

    Creates ipl3_dev.z64. Includes full debug support and a pre-signed trampoline.

    $ make

    Build Production Version

    Creates ipl3_prod.z64. This version is non-debug and must be correctly signed (e.g., using ipl3hasher) before use on real hardware.

    $ make clean
    $ make PROD=1

    Build Compatibility Version

    Creates ipl3_compat.z64. Also requires signing for real hardware.

    $ make clean
    $ make COMPAT=1

    Integrating a custom IPL3 into your project

    If you have built a custom ipl3_dev.z64 and want to test it with your game:

    1. Add N64_ROM_HEADER=<path/to/ipl3_dev.z64> to your game's Makefile using n64.mk.
    2. Alternatively, run make install in the IPL3 directory to embed it into n64tool by default (requires rebuilding n64tool).
  9. Deploy assets to an SD card for libdragon

    trunk

    To use assets (like sprites) loaded from an SD card in your libdragon project, you must place the required files inside a directory named /filesystem/ at the root of your SD card.

    This example demonstrates a fallback mechanism: the application will attempt to load images from the SD card if it is successfully mounted; if the SD card is not available, it will fall back to loading from the ROM. This ensures the code remains compatible with both real N64 hardware (using an SD card) and emulators (using the ROM).

  10. How to use IPL3 in compatibility mode

    trunk

    The compatibility build (ipl3_compat.z64) is designed for easy integration into existing homebrew applications that use flat binaries instead of ELFs.

    Behavior

    • Loading: Instead of an ELF, it loads 1 MiB (default) of a flat binary from ROM address 0x10001000 to the entrypoint specified in the header at offset 0x8.
    • Custom Load Size: IPL3 checks the word at offset 0x10 in the header to determine how much to load. If the value is 0 or too large, it defaults to 1 MiB.
    • Boot Flags: Flags are passed in low RDRAM (not DMEM) using this layout:
      • 0x80000300: TV type
      • 0x8000030C: Reset type
      • 0x80000318: Memory size

    Limitations

    • Does not support debugging or logging.
    • No error screens are shown (it will either boot or crash).
    • Not intended for commercial software/old games.
  11. Run libdragon ROMs on real N64 hardware

    trunk

    You can run libdragon ROMs on real hardware using development cartridges that support custom ROM loading via USB, serial, or MMC/SD cards.

    Supported Cartridges include:

    • 64drive
    • EverDrive64 (all models)
    • SC64
    • SummerCart64

    Debugging on Hardware: If your cartridge supports USB, use a loader that implements the libdragon debugging protocol to view logs in your PC console. Recommended loaders include:

    • UNFLoader
    • g64drive
    • ed64
  12. Integrate FreeType Amalgamation into your project

    trunk

    To use the FreeType font engine without linking against an external library, you can use the amalgamated source distribution. This involves adding the large concatenated source files directly to your project's build system.

    1. Add FreeTypeAmalgam.c to your project's source files.
    2. Include FreeTypeAmalgam.h in any source file where you need to call FreeType APIs.
    // In your source file
    #include "FreeTypeAmalgam.h"
    
    // Use FreeType APIs here...