/clones

A WIP NES emulator, most dev happening on git.sr.ht/~kingcons once-more-with-feeling branch

Primary LanguageCommon LispMIT LicenseMIT

Clones - An NES Emulator

Table of Contents

1 Links

Here are links to the current website and git repo.

2 Overview

Clones is an early-stage NES emulator written in Common Lisp.

It is inspired by long standing beliefs about the power of computers for experiential learning. See: Research Goals.

Why another emulator?

Reading things teaches people how to write. Analogous, if we are to place programming at the same fundamental level, using a program should teach how it works. But we don't see this.

Many NES emulators already exist on the web, the desktop, and elsewhere. Clones is intended to be a readable, tested, and compact code base sufficient for mostly accurate emulation of many but not all popular Nintendo titles.

However, my goal is not to be able to relive childhood nostalgia since that need is thoroughly solved. Clones exists to support curious programmers learning about how the system and its titles worked rather than being a vehicle for reliving the past. Running the games is just a prerequisite.

The codebase strives to be accessible for learning about emulation, sacrificing total accuracy and performance for clarity and ease of modification. Once some key games (Super Mario Bros, Mega Man 2) are playable, focus will shift towards building out debugging and reverse engineering tools.

In addition to the usual tools to disassemble memory or view VRAM, we hope to support building a directed graph of blocks and jumps as games are played. Afterwards, we'll provide tools for users to visualize and annotate the graph with notes about the code. This will move us towards our overall goal of making the high-level structure of programs "discoverable" through using them, calling back to the Tony Garnock-Jones quote above.

Current Status

Work has just begun so nothing is playable yet. Hang in there.

  • ROM Support: ✅

  • NROM Mapper: ✅

  • CPU Opcodes: ✅

  • PPU Registers: ✅

  • Rendering - Timing: ✅

  • Rendering - Backgrounds: ✅

  • Rendering - Sprites: ⌛

  • Rendering - Scrolling: ⌛

  • Input Handling: ✅

  • MMC1 Mapper: ✅

  • MMC3 Mapper: ❌

  • Audio Support: ❌

3 ROM Parsing

  • [function] PARSE-ROM PATHNAME

    Attempt to parse the file at PATHNAME as an Nintendo ROM, returning a property list suitable for passing to MAKE-INSTANCE for an appropriate MAPPER. An INVALID-ROM condition will be signalled if the header does not conform to the iNES format.

4 Mapper Interface

  • [class] MAPPER

    A Mapper is a virtual representation of a game cartridge, referenced by the PPU for purposes of accessing graphical data (CHR) and by the CPU for purposes of accessing program code (PRG).

  • [function] LOAD-ROM &OPTIONAL (PATHNAME (ASDF/SYSTEM:SYSTEM-RELATIVE-PATHNAME :CLONES "roms/nestest.nes"))

    Given a PATHNAME to a valid Nintendo ROM, process the file using PARSE-ROM and return an appropriate instance of MAPPER for the cartridge type of the game. An UNIMPLEMENTED-MAPPER condition will be signalled if the cartridge type is not yet supported by clones. If no PATHNAME is supplied, the NEStest ROM will be used.

  • [condition] UNIMPLEMENTED-MAPPER

    Signalled when no subclass of MAPPER implements the cartridge for the file supplied to LOAD-ROM.

  • [generic-function] MAPPER-PATHNAME OBJECT

  • [generic-function] GET-PRG MAPPER ADDRESS

    Retrieve the value at ADDRESS from the PRG bank of MAPPER.

  • [generic-function] SET-PRG MAPPER ADDRESS VALUE

    Set ADDRESS in the PRG bank of MAPPER to VALUE.

  • [generic-function] GET-CHR MAPPER ADDRESS

    Retrive the value at ADDRESS from the CHR bank of MAPPER.

  • [generic-function] SET-CHR MAPPER ADDRESS VALUE

    Set ADDRESS in the CHR bank of MAPPER to VALUE.

  • [accessor] MIRRORING MAPPER (:MIRRORING)

5 Memory Interface

  • [class] MEMORY

  • [function] MAKE-MEMORY &KEY (RAM (MAKE-OCTET-VECTOR 2048)) (PPU (MAKE-PPU)) (CONTROLLER (MAKE-CONTROLLER)) (CART (LOAD-ROM))

  • [function] FETCH MEMORY ADDRESS

  • [function] STORE MEMORY ADDRESS VALUE

  • [function] FETCH-WORD MEMORY ADDRESS

  • [function] FETCH-INDIRECT MEMORY START

  • [reader] MEMORY-PPU MEMORY (:PPU)

  • [reader] MEMORY-CART MEMORY (:CART)

  • [reader] MEMORY-CONTROLLER MEMORY (:CONTROLLER)

  • [accessor] MEMORY-DMA? MEMORY (= NIL)

  • [function] SWAP-CART MEMORY RELATIVE-PATH

6 Opcode Data

  • [function] FIND-OPCODE BYTE

    Find the OPCODE encoded as BYTE.

  • [structure-accessor] OPCODE-NAME OPCODE

  • [structure-accessor] OPCODE-CODE OPCODE

  • [structure-accessor] OPCODE-SIZE OPCODE

  • [structure-accessor] OPCODE-TIME OPCODE

  • [structure-accessor] OPCODE-ADDRESSING-MODE OPCODE

  • [structure-accessor] OPCODE-ACCESS-PATTERN OPCODE

7 Disassembler

  • [function] DISASM MEMORY START END

    Loop through MEMORY from START to END printing disassembly for each instruction found in the specified range. An error will be thrown if illegal instructions are present or if the start index is not the beginning of a 6502 instruction.

  • [function] DISASSEMBLE-INSTRUCTION MEMORY INDEX &KEY (STREAM T)

    Disassemble a single instruction from MEMORY beginning at INDEX. STREAM is the FORMAT destination of the disassembly output.

8 CPU Core

  • [class] CPU

  • [function] MAKE-CPU &KEY (MEMORY (MAKE-MEMORY))

  • [accessor] CPU-MEMORY CPU (:MEMORY)

  • [accessor] CPU-CYCLES CPU (= 0)

  • [function] SINGLE-STEP CPU

    Step the CPU over the current instruction.

  • [function] RESET CPU

  • [function] NOW CPU &KEY (STREAM T)

    Disassemble the current instruction pointed to by the CPU's program counter. STREAM is the FORMAT destination for the disassembly.

  • [function] NMI CPU

  • [function] CHANGE-GAME CPU RELATIVE-PATH

9 Picture Processing Unit

  • [class] PPU

  • [function] MAKE-PPU &KEY (NAME-TABLE (MAKE-OCTET-VECTOR 4096)) (CART (LOAD-ROM))

  • [function] READ-PPU PPU ADDRESS

  • [function] WRITE-PPU PPU ADDRESS VALUE

  • [function] SET-VBLANK! PPU VALUE

  • [function] VBLANK-NMI? PPU

  • [function] READ-PALETTE PPU ADDRESS

  • [function] GET-MIRRORING PPU

  • [function] QUAD-POSITION PPU

  • [function] RENDER-SPRITES? PPU

  • [function] RENDER-BACKGROUND? PPU

  • [function] RENDERING-ENABLED? PPU

  • [class] SPRITE

  • [function] MAKE-SPRITE PPU NUMBER

  • [function] EVALUATE-SPRITES PPU SCANLINE

  • [function] SPRITE-ZERO-HIT? PPU

  • [function] SET-SPRITE-OVERFLOW! PPU VALUE

  • [function] SET-SPRITE-ZERO-HIT! PPU VALUE

  • [function] FETCH-SCANLINE-BYTES PPU TILE-DESCRIPTOR

    Fetch the low and high bytes of the pattern matching TILE-DESCRIPTOR that are appropriate for display on the current scanline of PPU.

  • [function] FETCH-TILE-BYTES PPU TILE-DESCRIPTOR

    Fetch all 16 bytes of the the pattern corresponding to TILE-DESCRIPTOR.

  • [generic-function] FLIP-X? TILE-DESCRIPTOR

    Check whether the X-axis of TILE-DESCRIPTOR should be flipped.

  • [generic-function] FLIP-Y? TILE-DESCRIPTOR

    Check whether the Y-axis of TILE-DESCRIPTOR should be flipped.

  • [generic-function] COMPUTE-X-OFFSET PPU TILE-DESCRIPTOR

    Compute the X offset for the tile currently being rendered by PPU.

  • [function] PALETTE-LOW-BITS LOW-BYTE HIGH-BYTE INDEX

  • [generic-function] PALETTE-HIGH-BITS PPU TILE-DESCRIPTOR

    Determine the 2 high bits of the palette index for TILE-DESCRIPTOR.

  • [function] FINE-SCROLL-VERTICAL! PPU

    A scroll operation that conceptually occurs at the end of each scanline.

  • [function] COARSE-SCROLL-HORIZONTAL! PPU

    A scroll operation that conceptually occurs at the end of each 8-pixel tile.

  • [function] SYNC-VERTICAL-SCROLL! PPU

  • [function] SYNC-HORIZONTAL-SCROLL! PPU

10 The Rendering Logic

  • [class] RENDERER

  • [function] MAKE-RENDERER &KEY (PPU (MAKE-PPU)) (ON-NMI (CONSTANTLY NIL)) ON-FRAME

  • [generic-function] SYNC RENDERER CPU FRAMEBUFFER

    Synchronize the renderer to the CPU and return the next scanline.

  • [function] RENDER-PIXEL FRAMEBUFFER X Y COLOR-INDEX

11 Input Handling

  • [class] CONTROLLER

  • [function] MAKE-CONTROLLER

  • [function] READ-CONTROLLER CONTROLLER

  • [function] RESET-CONTROLLER CONTROLLER

  • [function] UPDATE-BUTTON CONTROLLER BUTTON VALUE

12 Debugging Utilities

  • [function] FOR-SPRITES PPU CALLBACK

  • [function] FOR-BACKGROUND PPU CALLBACK &KEY (NAME-TABLE 0)

  • [function] DUMP-GRAPHICS BUFFER PPU &KEY ITERATOR MARGIN

[generated by MGL-PAX]