PICO-8 Wiki
(→‎Draw state: Zep described one of the undocumented addresses as suppressing palette reset)
(→‎Draw state: screen mode)
Line 118: Line 118:
   
 
0x5f28-0x5f2b: Camera position ([[Camera|<code>camera()</code>]]). The x and y offsets are stored as 16-bit signed integers with the least significant byte first. 0x5f28-0x5f29=x offset, 0x5f2a-0x5f2b=y offset.
 
0x5f28-0x5f2b: Camera position ([[Camera|<code>camera()</code>]]). The x and y offsets are stored as 16-bit signed integers with the least significant byte first. 0x5f28-0x5f29=x offset, 0x5f2a-0x5f2b=y offset.
  +
  +
0x5f2c: Bit 2 (value 4) controls what this value does. If clear, bits 0 and 1 (values 1 and 2) control horizontal and vertical pixel-doubling. If bit 2 is set, they instead control screen mirroring, left-to-right and top-to-bottom, respectively. Thus, a value of 3 would produce a 64x64 screen, and a value of 7 would produce a 4-way kaleidoscope effect.
   
 
0x5f2e: (undocumented, but confirmed by zep) If set to 1, causes the current palette scheme (see [[Pal|<code>pal()</code>]] or the 0x5f00-0x5f1f memory range, above) to persist instead of being reset at the end of the program.
 
0x5f2e: (undocumented, but confirmed by zep) If set to 1, causes the current palette scheme (see [[Pal|<code>pal()</code>]] or the 0x5f00-0x5f1f memory range, above) to persist instead of being reset at the end of the program.

Revision as of 10:35, 24 April 2018

Pico-8 has 32 kilobytes of addressable memory, used for graphics, map, sound, music, and direct access to hardware features such as persistent cartridge data and GPIO pins. Programs can read from and write to this data using peek() and poke().

While many games can use the built-in functions for graphics and sound, memory access enables advanced techniques such as repurposing memory regions or generating graphics and sound data algorithmically. For features such as the GPIO pins, peek() and poke() are currently the only way to access the feature.

The first 16 kilobytes are copied from the cartridge into memory when the cartridge is loaded. When the cartridge changes a value in memory, it is only changed in memory and not in the cartridge itself.

You can use the cstore() function to write memory data to the cartridge file. You can also use the reload() function to load cartridge data back into memory, or load a region of memory from another cartridge file.

The Lua program stack (variables, etc.) is not stored in addressable memory and cannot be accessed directly by the program.

See also P8FileFormat, P8PNGFileFormat.

Memory map

This is the high-level memory map for addressable memory:

Start End Purpose
0x0 0x0fff Sprite sheet (0-127)
0x1000 0x1fff Sprite sheet (128-255) / Map (rows 32-63) (shared)
0x2000 0x2fff Map (rows 0-31)
0x3000 0x30ff Sprite flags
0x3100 0x31ff Music
0x3200 0x42ff Sound effects
0x4300 0x5dff General use
0x5e00 0x5eff Persistent cart data (64 numbers = 256 bytes)
0x5f00 0x5f3f Draw state
0x5f40 0x5f7f Hardware state
0x5f80 0x5fff GPIO pins (128 bytes)
0x6000 0x7fff Screen data (8k)

The in-memory data formats for each section are described below.

Sprite sheet

The sprite sheet is represented in memory as one large image, 128 x 128 pixels. Each sprite tile is an 8 x 8 region in this image. Each sprite tile gets an ID, counting from 0, left to right, top to bottom.

Each pixel can be one of 16 colors, and is represented by 4 bits. An 8-bit byte represents two pixels, horizontally adjacent, where the most significant (leftmost) 4 bits is the right pixel of the pair, and the least significant 4 bits is the left pixel.

Other than this swapping within the byte, pixels are arranged in memory going left to right, top to bottom, for the entire 128 x 128 pixel image (using 128 * 64 = 8,192 bytes).

The bottom half of the sprite sheet and the bottom half of the map region overlap in memory. Typically, a game uses this region for only one purpose or the other.

Map

The map is 128 tiles wide by 64 tiles high. Each tile is one of the 256 tiles from the sprite sheet, one byte per tile (using 128 * 64 = 8,192 bytes). The value is the sprite ID.

Sprite flags

Each sprite tile has 8 flags, each of which can be on or off. One byte stores the flags for a sprite tile. Bytes are arranged by sprite ID, for a total of 256 bytes.

In the graphics editor, the flags are arranged left to right from LSB to MSB: red=1, orange=2, yellow=4, green=8, blue=16, purple=32, pink=64, peach=128.

Music

There are 64 music patterns. Each music pattern uses four bytes to assign a sound effect or silence to each of four channels. (4 * 64 = 256 bytes.)

If a sound effect is assigned to a channel, bit 6 is 0, and bits 5-0 are the sound ID (0 through 63). If the channel is silent, bit 6 is 1, and bits 5-0 are the channel number (1, 2, 3, or 4).

Bit 7 is used to describe the flags for the music pattern. Bit 7 of the first byte (channel 1) is "stop at end of pattern." Bit 7 of the second byte (channel 2) is "end pattern loop." Bit 7 of the third byte (channel 3) is "begin pattern loop." (Bit 7 of the fourth byte is unused.)

Sound effects

There are 64 sound effects. Each sound effect is 68 bytes, with two bytes for each of 32 notes and then one byte for the editor mode, one byte for the speed, two bytes for the loop range (start, end). (64 * 68 = 4,352 bytes.)

The effect speed is a value between 0 and 255, representing the duration of each note in the effect, as a multiple of 1/128 seconds. Using the full effect length of 32 notes, with a speed of 1, the full effect plays in 1/4 second. With a speed of 4, the full effect plays in 1 second.

In an effect used for a music pattern, you can calculate beats per minute based on how many notes per "beat." For example, if an effect plays a "beat" every four notes in an effect, a speed of 15 is equivalent to 15/128 seconds per note, 15*4/128 seconds per four notes (one beat), (15*4)/(128*60) minutes per beat, or (128*60)/(15*4) = 128 beats per minute.

Each note is encoded in 16 bits, least significant byte first, like so:

w2-w1-pppppp c-eee-vvv-w3

  • eee: effect (0-7)
  • vvv: volume (0-7)
  • w3w2w1: waveform (0-7)
  • pppppp: pitch (0-63)
  • c: when c is 1, waveform is a custom instrument corresponding to sfx 0-7; otherwise it is one of the eight built-in waveforms (Pico-8 0.1.11)

General use

The memory region from 0x4300 to 0x5dff is available for the program to use for any purpose.

This region is not loaded from the cartridge, though you can use the reload() function to copy data into this region from a cartridge file.

Persistent cart data

After persistent data is initialized with the cartdata() function, this 256-byte region represents the 64 number values accessible by dset() and dget().

As with all Pico-8 numbers, the number is stored as a fixed point value, using 16 bits (two bytes) for the integer portion (signed) and 16 bits for the fractional portion.

Draw state

This memory region represents the current draw state. The values are as follows:

0x5f00-0x5f1f: Palette filtering (pal(), palt()). 0x5f00-0x5f0f is palette #0 (the draw palette), and 0x5f10-0x5f1f is palette #1 (the screen palette). The index is the original color number, and bits 0-7 are the replacement color number. Bit 8 indicates whether the color should be treated as transparent (1=true).

0x5f20-0x5f23: Clipping region (clip()). The bounding box is described in four bytes, as coordinates from the top-left origin (0,0): 0x5f20=x1, 0x5f21=y1, 0x5f22=x2, 0x5f23=y2. Notice that this differs from the arguments to clip(): x2=x1+w, y2=y1+h.

0x5f24: (unknown, please update this if you know)

0x5f25: Pen color (color()). The value is a color number from 0-15.

0x5f26-0x5f27: Print cursor (cursor()). 0x5f26=x, 0x5f27=y.

0x5f28-0x5f2b: Camera position (camera()). The x and y offsets are stored as 16-bit signed integers with the least significant byte first. 0x5f28-0x5f29=x offset, 0x5f2a-0x5f2b=y offset.

0x5f2c: Bit 2 (value 4) controls what this value does. If clear, bits 0 and 1 (values 1 and 2) control horizontal and vertical pixel-doubling. If bit 2 is set, they instead control screen mirroring, left-to-right and top-to-bottom, respectively. Thus, a value of 3 would produce a 64x64 screen, and a value of 7 would produce a 4-way kaleidoscope effect.

0x5f2e: (undocumented, but confirmed by zep) If set to 1, causes the current palette scheme (see pal() or the 0x5f00-0x5f1f memory range, above) to persist instead of being reset at the end of the program.

0x5f30: (undocumented) If set to 1, suppresses the next attempt to bring up the pause menu. This can be done as late as discovering the pause button has been pressed this frame:

  if(band(btn(),64)) poke(0x5f30,1)

0x5f2c-0x5f3f otherwise appear to be either undocumented or reserved for future use.

Hardware state

These memory addresses represent or control various aspects of the hardware. These are undocumented.

GPIO pins

This experimental feature provides programs access to the GPIO (general purpose input/output) hardware pins of a Raspberry Pi or CHIP device. These addresses can be used to accept digital input from or write digital output to devices connected to the pins.

Screen data

This 8,192-byte (8 kilobyte) region contains the graphics buffer. This is what is modified by the built-in drawing functions, and is what is copied to the actual display at the end of the game loop or by a call to flip().

See the description of the sprite sheet, above, for information on how this image is represented in memory.