PICO-8 Wiki
Register
(→‎Hardware state: add read mask)
(I just wanted to change it to passive voice, but doing so was so tricky that I basically ended up rewriting it. sorry to the anon contributor—it was still a very welcome filling of a knowledge gap!)
Tag: Source edit
(42 intermediate revisions by 9 users not shown)
Line 1: Line 1:
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|<code>peek()</code>]] and [[Poke|<code>poke()</code>]].
+
PICO-8 has 64 [[KiB]] of addressable memory, used for graphics, map, sound, music, and direct access to hardware features such as persistent cartridge data and GPIO pins. Normally only the lower 32 KiB are accessible, while the upper 32 KiB are protected, with the PICO-8 fantasy lore suggesting that the kernel and the game itself might reside there. However, it is possible to [[Memory#EnableUpperRAM|switch the upper 32 KiB to RAM]]. Programs can read from and write to this memory using <code>[[Peek|peek()]]</code> and <code>[[Poke|poke()]]</code>.
   
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|<code>peek()</code>]] and [[Poke|<code>poke()</code>]] are currently the only way to access the feature.
+
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, <code>peek()</code> and <code>poke()</code> 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.
+
The first 16 KiB 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.
   
The [[Cstore|<code>cstore()</code>]] function can be used to write memory data to the cartridge file. The [[Reload|<code>reload()</code>]] function can also be used to load cartridge data back into memory, or load a region of memory from another cartridge file.
+
The <code>[[Cstore|cstore()]]</code> function can be used to write memory data to the cartridge file. The <code>[[Reload|reload()]]</code> function can also be used 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.
 
The Lua program stack (variables, etc.) is not stored in addressable memory and cannot be accessed directly by the program.
Line 30: Line 30:
 
| 0x3200 || 0x42ff || Sound effects
 
| 0x3200 || 0x42ff || Sound effects
 
|-
 
|-
| 0x4300 || 0x5dff || General use (or work RAM)
+
| 0x4300 || 0x55ff || General use (or work RAM)
  +
|-
  +
|0x5600
  +
|0x5dff
  +
|General use / custom font (0.2.2+)
 
|-
 
|-
| 0x5e00 || 0x5eff || Persistent cart data (64 numbers = 256 bytes)
+
| 0x5e00||0x5eff || Persistent cart data (64 numbers = 256 bytes)
 
|-
 
|-
| 0x5f00 || 0x5f3f || [[DrawState|Draw state]]
+
| 0x5f00||0x5f3f||[[DrawState|Draw state]]
 
|-
 
|-
| 0x5f40 || 0x5f7f || Hardware state
+
|0x5f40 ||0x5f7f||Hardware state
 
|-
 
|-
| 0x5f80 || 0x5fff || GPIO pins (128 bytes)
+
|0x5f80||0x5fff || GPIO pins (128 bytes)
 
|-
 
|-
| 0x6000 || 0x7fff || Screen data (8k)
+
|0x6000||0x7fff|| Screen data (8k)
 
|}
 
|}
   
 
The in-memory data formats for each section are described below.
 
The in-memory data formats for each section are described below.
   
== Sprite sheet ==
+
== 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.
 
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. Pixels are stored from left to right, top to bottom.
+
Each pixel can be one of 16 colors, and is represented by a 4-bit value, also known as a ''nybble''. Thus, 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. Pixels are stored from left to right, top to bottom.
   
 
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).
 
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).
Line 55: Line 59:
 
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.
 
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.
   
'''0x0000-0x0fff / 0-4095'''
+
'''0x0000..0x0fff / 0..4095'''
  +
:The upper 64 rows in the sprite sheet. Each 64-byte row contains 128 pixels. Each byte contains two adjacent pixels, with the lo 4 bits being the left/even pixel and the hi 4 bits being the right/odd pixel.
 
  +
:The upper 64 rows of pixels (that is, upper 8 rows of sprites) in the sprite sheet. Each 64-byte row contains 128 pixels. Each byte contains two adjacent pixels, with the low 4 bits being the left/even pixel and the high 4 bits being the right/odd pixel.
  +
  +
'''0x1000..0x1fff / 4096..8191'''
  +
  +
:The lower 64 rows of pixels (that is, lower 8 rows of sprites) in the sprite sheet. Same format as above. Overlaps ''lower'' half of Map (see below).
  +
  +
If '''sp''' is the sprite number, then the memory address at which a sprite's data starts is given by the expression:
  +
  +
<syntaxhighlight lang="lua">
  +
addr = 512 * (sp \ 16) + 4 * (sp % 16)
  +
</syntaxhighlight>
  +
  +
Explanation: think of the sprite sheet as a grid of 16x16 sprites. Then the high 4 bits of the sprite number (sp \ 16) indicates the row number (0-15), and the low 4 bits of the sprite number (sp % 16) indicates the column number (0-15). Every row of this grid is made up of 16 sprites, so each row occupies 16 sprites * 32 bytes/sprite = 512 bytes. This explains the 512 * (sp \ 16) part. After that, we have to locate it within the row. The column is sp % 16, and we have to walk forward 4 bytes for each sprite (8 pixels), so we have to move forward sp % 16 bytes.
   
  +
The entire sprite is NOT stored at that position though, because the sprite sheet is a single image, you will only find, at that address, the 4 bytes (8 pixels) that correspond to the top row of the sprite. If you want the next row, you have to increment addr by 64 (that jumps over an entire row of 128 pixels = 64 bytes). In graphics parlance, the stride (amount you add to get from one row to the next in the image) is 64 bytes.
'''0x1000-0x1fff / 4096-8191'''
 
:The lower 64 rows in the sprite sheet. Same format as above. Overlaps ''lower'' half of Map (see below).
 
   
== Map ==
+
==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.
 
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.
Line 67: Line 83:
 
The map is read from left to right, top to bottom order.
 
The map is read from left to right, top to bottom order.
   
'''0x1000-0x1fff / 4096-8191'''
+
'''0x1000..0x1fff / 4096..8191'''
  +
 
:The ''lower'' 32 rows of the map. Each row contains 128 tiles. Each byte contains one tile index. Overlaps lower half of Sprite Sheet (see above).
 
:The ''lower'' 32 rows of the map. Each row contains 128 tiles. Each byte contains one tile index. Overlaps lower half of Sprite Sheet (see above).
   
'''0x2000-0x2fff / 8192-12287'''
+
'''0x2000..0x2fff / 8192..12287'''
  +
 
:The upper 32 rows of the map. Each row contains 128 tiles. Each byte contains one tile index.
 
:The upper 32 rows of the map. Each row contains 128 tiles. Each byte contains one tile index.
   
== Sprite flags ==
+
== 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.
 
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.
Line 79: Line 97:
 
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.
 
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.
   
  +
Note that the binary representation of the byte is reverse from the order of the flag buttons in the sprite editor. For example, if a sprite only has the orange and yellow flags set, the byte representing its flags will be '''0b00000110'''.
'''0x3000-0x30ff / 12288-12543'''
 
  +
:Each byte represents the flags for the associated sprite.
 
  +
'''0x3000..0x30ff / 12288..12543'''
  +
  +
: Each byte represents the flags for the associated sprite.
  +
  +
==Music==
  +
  +
There are 64 music frames. Each frame (from 0 to 63) uses four consecutive bytes corresponding with the four PICO-8 sound channels, for a total of 256 bytes.
  +
  +
If bit 6 (value 64) is 0, then the corresponding channel is enabled with the sound ID specified by bits 5-0 (values 0 to 63). If bit 6 is 1, the channel is disabled with bits 5-0 being unused.
   
  +
Bit 7 (value 128) does not have a function associated per-channel, but is used to describe the flags for the frame. The 1st byte of the frame is "begin loop." The 2nd byte is "end loop." The 3rd byte is "stop at end." ''Bit 7 in the 4th byte is either unknown or unused, so please update this section if you know its purpose.''
== Music ==
 
   
  +
== Sound effects==
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.)
 
   
  +
There are 64 sound effects. Each sound effect is 68 bytes, with two bytes for each of 32 notes, followed by one byte encoding the editor mode and filter switches, one byte for the speed, and two bytes for the loop parameters (start, end). (64 * 68 = 4,352 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 not used.
 
   
  +
The editor mode and filter switches can be decoded and assigned to Lua variables as follows:<syntaxhighlight lang="lua">
Bit 7 is used to describe the flags for the music pattern. Bit 7 of the first byte (channel 1) is "begin pattern loop." Bit 7 of the second byte (channel 2) is "end pattern loop." Bit 7 of the third byte (channel 3) is "stop at end of pattern." (Bit 7 of the fourth byte is unused.)
 
  +
-- compute address of sfx
  +
sfxaddr = 0x3200 + sfxid*68
   
  +
byte = @(sfxaddr+64)
== Sound effects ==
 
  +
editormode = byte&1 > 0 -- set to true if in tracker mode
  +
noiz = byte&2 > 0
  +
buzz = byte&4 > 0
  +
detune = byte\8%3
  +
reverb = byte\24%3
  +
dampen = byte\72%3
  +
</syntaxhighlight>They can also be encoded back as follows:<syntaxhighlight lang="lua">
  +
-- compute address of sfx
  +
sfxaddr = 0x3200 + sfxid*68
   
  +
byte = editormode and 1 or 0 -- set to 1 if in tracker mode
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.)
 
  +
byte |= noiz and 2 or 0
  +
byte |= buzz and 4 or 0
  +
byte += detune * 8
  +
byte += reverb * 24
  +
byte += dampen * 72
  +
poke(sfxaddr+64, byte)
  +
</syntaxhighlight>The binary (2-level) switches are simply given their own bits, but the 3-level switches are stored in a way that allows all combinations of those (3 ^ 3 = 27) to be expressed within the remaining 5 of the available 8 bits. 5 bits allow for up to 32 possible values to be stored (0 to 31), so this decision was made.
   
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.
+
The effect speed is a value between 0 and 255, representing the duration of each note in the effect, as a multiple of 183 ticks (with 22050 ticks in a second), approximately 1/120 of a second. A speed of 0 appears to be treated as 1. Using the full effect length of 32 notes, with a speed of 1, the full effect plays approximately 1/4 second (0.26557823129 seconds, or 32 * 183 / 22050). With a speed of 4, the full effect plays in 1.062 seconds.
   
In an effect used for a music pattern, beats per minute can be calculated 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.
+
In an effect used for a music pattern, beats per minute can be calculated 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/120 seconds per note, 15*4/120 seconds per four notes (one beat), (15*4)/(120*60) minutes per beat, or (120*60)/(15*4) = 120 beats per minute. (Note that we take 120 as an approximation of 22050/183 = 120.491803279)
   
Each note is encoded in 16 bits, in [https://en.wikipedia.org/wiki/Endianness Little Endian] style, with the low 8 bits in the first byte, and the hi 8 bits in the second, formatted like so:
+
Each note is encoded in 16 bits, in [https://en.wikipedia.org/wiki/Endianness Little Endian] style, with the low 8 bits in the first byte, and the high 8 bits in the second, formatted like so:
   
<div align=center>
+
<div align="center">
 
{| class="article-table" style="display: inline-table;"
 
{| class="article-table" style="display: inline-table;"
!colspan=8 align=center|Second byte / Hi 8 bits
+
! colspan="8" align="center" |Second byte / High 8 bits
 
|-
 
|-
 
|c
 
|c
Line 109: Line 154:
 
|e
 
|e
 
|v
 
|v
|v
+
| v
 
|v
 
|v
 
|w
 
|w
 
|}
 
|}
 
{| class="article-table" style="display: inline-table;"
 
{| class="article-table" style="display: inline-table;"
!colspan=8 align=center|First byte / Lo 8 bits
+
! colspan="8" align="center" |First byte / Low 8 bits
 
|-
 
|-
 
|w
 
|w
Line 127: Line 172:
 
</div>
 
</div>
   
* <code>c</code>: 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+)
+
*<code>c</code>: 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+)
* <code>eee</code>: effect (0-7)
+
*<code>eee</code>: effect (0-7)
* <code>vvv</code>: volume (0-7)
+
*<code>vvv</code>: volume (0-7)
* <code>www</code>: waveform (0-7)
+
*<code>www</code>: waveform (0-7)
* <code>pppppp</code>: pitch (0-63)
+
*<code>pppppp</code>: pitch (0-63)
   
  +
==General use==
For example, a note's pitch and effect can be seen using <code>peek(0x3200 + 68*track + 2*time)</code>, and instrument and volume by <code>peek(0x3200 + 68*track + 2*time + 1)</code>. So if 30 was seen for instrument and volume, they are stored in bits <code>0b0011110</code> so the instrument is <code>0b001</code> (1) and volume is <code>0b111</code> (7); the last bit is used for sfx instrument flag, 0 if off, 1 if on. <!-- TODO: This bit really needs to be re-worded. It's kind of hard to follow. -->
 
   
  +
'''0x4300..0x55ff / 17152..22015'''
== General use ==
 
   
'''0x4300-0x5dff / 17152-24063'''
 
 
This memory region is available for the program to use for any purpose.
 
This memory region is available for the program to use for any purpose.
   
This region is not loaded from the cartridge, though the [[Reload|<code>reload()</code>]] function can be used to copy data into this region from a cartridge file.
+
This region is not loaded from the cartridge, though the <code>[[Reload|reload()]]</code> function can be used to copy data into this region from a cartridge file.
   
(Undocumented?) This region is not reset when loading another cart via [[Load|load()]], so can be used for passing data to and from the loaded cart.
+
(Undocumented?) This region is not reset when loading another cart via <code>[[Load|load()]]</code>, so can be used for passing data to and from the loaded cart.
   
== Persistent cart data ==
+
==General use / custom font==
   
'''0x5e00-0x5eff / 24064-24319'''
+
'''0x5600..0x5dff / 22016..24063'''
  +
After persistent data is initialized with the [[Cartdata|<code>cartdata()</code>]] function, the 256-byte region from 0x5e00 to 0x5eff represents the 64 number values accessible by [[Dset|<code>dset()</code>]] and [[Dget|<code>dget()</code>]]. These numbers are stored in the same 4-byte, [https://en.wikipedia.org/wiki/Endianness little endian], 16.16 fixed-point format used by [[Peek4|<code>peek4()</code>]] and [[Poke4|<code>poke4()</code>]].
 
  +
This memory region is available for the program to use for any purpose, like the 0x4300..0x55ff region above. Starting with version 0.2.2, this is also used for storing the custom font (use [[P8SCII]] code 14 to select this font, and 15 to return back to the default font).
  +
  +
There are 256 characters mapped to each of the 256 P8SCII codes. Each character consists of 8 bytes for each of its 8 rows of pixels, with the first byte being the top-most row, for a total of 2 KB (256 * 8 = 2048 bytes). Each byte consists of 8 pixels, with the left-most pixel in the LSB (bit 0, value 1), and the right-most pixel in the MSB (bit 7, value 128). This is reverse from the binary representation.
  +
  +
Since character 0 (null) is never drawn, its data in memory is purposed by PICO-8 to store default attributes for the font, which are all unsigned bytes:
  +
  +
'''0x5600 / 22016''' - Character width (characters <128)
  +
  +
'''0x5601 / 22017''' - Character width (characters >=128)
  +
  +
'''0x5602 / 22018''' - Character height
  +
  +
'''0x5603 / 22019''' - Draw X offset
  +
  +
'''0x5604 / 22020''' - Draw Y offset
  +
  +
'''0x5605..0x5607 / 22021..22023''' - ''(Unknown. Please document the significance of these bytes if you know.)''
  +
  +
==Persistent cart data==
  +
  +
'''0x5e00..0x5eff / 24064..24319'''
  +
  +
After persistent data is initialized with the <code>[[Cartdata|cartdata()]]</code> function, the 256-byte region from 0x5e00 to 0x5eff represents the 64 number values accessible by <code>[[Dset|dset()]]</code> and <code>[[Dget|dget()]]</code>. These numbers are stored in the same 4-byte, [https://en.wikipedia.org/wiki/Endianness little endian], 16.16 fixed-point format used by <code>[[Peek4|peek4()]]</code> and <code>[[Poke4|poke4()]]</code>.
   
 
Note that using <code>dset()</code> and <code>dget()</code> partitions this memory into 64 standard PICO-8 numbers, but these are just helper functions and they are not mandatory. This memory region can be formatted in any desired manner. For instance, a bar chart with up to 51 bars could be encoded by saving a width for each bar and its color index, with the width being a full PICO-8 number and the color just being a byte:
 
Note that using <code>dset()</code> and <code>dget()</code> partitions this memory into 64 standard PICO-8 numbers, but these are just helper functions and they are not mandatory. This memory region can be formatted in any desired manner. For instance, a bar chart with up to 51 bars could be encoded by saving a width for each bar and its color index, with the width being a full PICO-8 number and the color just being a byte:
Line 164: Line 231:
 
</syntaxhighlight>
 
</syntaxhighlight>
   
== Draw state ==
+
==Draw state==
   
 
This memory region represents the current [[DrawState|draw state]]. The values are as follows:
 
This memory region represents the current [[DrawState|draw state]]. The values are as follows:
   
'''0x5f00-0x5f0f / 24320-24335'''
+
'''0x5f00..0x5f0f / 24320..24335'''
:Draw palette look-up table ([[Pal|<code>pal()</code>]], [[Palt|<code>palt()</code>]]). When PICO-8 is asked to draw a certain 4-bit color index, it looks up the color's index in this table to decide which ''actual'' 4-bit color index to write to screen memory. The 16 values in this table should have their lower 4 bits set to 0-15, to indicate which index is actually written to screen memory, while bit 5 should be either 0 for normal operation, or 1 (i.e. add 16 to the index) if the color index is to be transparent.
 
   
  +
:Draw palette look-up table (<code>[[Pal|pal()]]</code>, <code>[[Palt|palt()]]</code>). When PICO-8 is asked to draw a certain 4-bit color index, it looks up the color's index in this table to decide which 4-bit color index it should be remapped with to eventually be written to screen memory. The 16 values in this table should have their lower nibble (bits 0-3) set to 0-15, to indicate which index is actually written to screen memory, while their upper nibble (bits 4-7) should be either zero for normal operation, or non-zero (i.e. the byte value is from 16 to 255) if the color index is to be transparent.
'''0x5f10-0x5f1f / 24336-24351'''
 
:Screen palette look-up table ([[Pal|<code>pal(...,1)</code>]]). PICO-8 reads this table while converting the color indices in screen memory into system ("hardware") colors to be shown on its display. As of this writing, there are ''officially'' only 16 system colors available, whose values range from 0 to 15. However, an additional, but undocumented, 16 colors appear to be available at values from 128 to 143, and [https://twitter.com/lexaloffle/status/1169094824474992640 zep appears to be fine with us knowing this].
 
   
'''0x5f20-0x5f23 / 24352-24355'''
+
'''0x5f10..0x5f1f / 24336..24351'''
:Clipping rectangle ([[Clip|<code>clip(x,y,w,h)</code>]]):
 
   
  +
: Screen palette look-up table (<code>[[Pal|pal(...,1)]]</code>). PICO-8 reads this table while converting the color indices in screen memory into system ("hardware") colors to be shown on its display. As of this writing, there are ''officially'' only 16 system colors available, whose values range from 0 to 15. However, an additional, but undocumented, 16 colors appear to be available at values from 128 to 143, and [https://twitter.com/lexaloffle/status/1169094824474992640 zep appears to be fine with us knowing this]. Bits 4-6 (values 16, 32, 64) appear to be ignored.
:*0x5f20 / 24352: x_begin (no pixels < x_begin will be drawn)
 
:*0x5f21 / 24353: y_begin (no pixels < y_begin will be drawn)
 
:*0x5f22 / 24354: x_end (no pixels >= x_end will be drawn)
 
:*0x5f23 / 24355: y_end (no pixels >= x_end will be drawn)
 
   
  +
'''0x5f20..0x5f23 / 24352..24355'''
:These are somewhat different from the <code>clip(x,y,w,h)</code> arguments. Use <code>clip(xb,yb,xe-xb,ye-yb)</code> to set a clip rectangle using values like these.
 
   
  +
:Clipping rectangle (<code>[[Clip|clip(x,y,w,h)]]</code>):
:Note: Inside <code>clip()</code> the rectangle is clamped to the edges of the display before the GPU is configured. Expect x,y begin values to be in the range 0..127, and x,y end values to be in the slightly-larger range 0..128.
 
  +
:*0x5f20 / 24352: '''x_begin''' (no pixels < '''x_begin''' will be drawn)
  +
:*0x5f21 / 24353: '''y_begin''' (no pixels < '''y_begin''' will be drawn)
  +
:*0x5f22 / 24354: '''x_end''' (no pixels >= '''x_end''' will be drawn)
  +
:*0x5f23 / 24355: '''y_end''' (no pixels >= '''y_end''' will be drawn)
  +
:
  +
:If '''x_end''' is less than or equal to '''x_begin''', or '''y_end''' is less than or equal to '''y_begin''', then no visible clipping area is formed, effectively blocking rendering.
  +
:These are somewhat different from the <code>clip(x,y,w,h)</code> arguments. Use <code>clip(xb,yb,xe-xb,ye-yb)</code> to set a clip rectangle using values like these, or starting with 0.2.2, <code>poke(0x5f20,xb,yb,xe,ye)</code> to save tokens.
  +
: Note: <code>clip()</code> clamps the rectangle to the edges of the display. Expect x,y begin values to be in the range 0..127, and x,y end values to be in the slightly-larger range 0..128.
   
 
'''0x5f24 / 24356'''
 
'''0x5f24 / 24356'''
  +
 
:''(unknown, please update this if you know)''
 
:''(unknown, please update this if you know)''
   
 
'''0x5f25 / 24357'''
 
'''0x5f25 / 24357'''
:Pen color ([[Color|<code>color()</code>]]). The bottom 4 bits are the current color index, from 0-15. The top 4 bits are typically 0 and unused, but when using fill patterns, they will be the secondary color index.
 
   
  +
:Pen color (<code>[[Color|color()]]</code>). The bottom 4 bits (0-3) are the current color index, from 0-15. The top 4 bits (4-7) are typically 0 and unused, but when using fill patterns, they will be the secondary color index.
'''0x5f26-0x5f27 / 24358-24359'''
 
:Print cursor ([[Cursor|<code>cursor()</code>]]). 0x5f26=x, 0x5f27=y.
 
   
'''0x5f28-0x5f2b / 24360-24363'''
+
'''0x5f26..0x5f27 / 24358..24359'''
  +
: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.
 
  +
:Print cursor (<code>[[Cursor|cursor()]]</code>). 0x5f26=x, 0x5f27=y.
  +
  +
'''0x5f28..0x5f2b / 24360..24363'''
  +
  +
:Camera position (<code>[[Camera|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 / 24364'''
 
'''0x5f2c / 24364'''
  +
:This value sets the draw mode to normal, stretching, mirroring, flipping, or rotating.
 
  +
:This value sets the screen transformation mode to be variations of stretching, mirroring, flipping, or rotating. This can't be changed in-between draw calls; it affects the entire screen.
:* 0 = normal mode
 
  +
:*0 = normal mode
:* 1 = horizontal stretch, 64x128px screen, left half of normal screen
 
:* 2 = vertical stretch, 128x64px screen, top half of normal screen
+
:*1 = horizontal stretch, 64x128 screen, left half of normal screen
:* 3 = both stretch, 64x64px screen, top left quarter of normal screen
+
:*2 = vertical stretch, 128x64 screen, top half of normal screen
  +
:*3 = both stretch, 64x64 screen, top left quarter of normal screen
 
:* 5 = horizontal mirroring, left half copied and flipped to right half
 
:* 5 = horizontal mirroring, left half copied and flipped to right half
:* 6 = vertical mirroring, top half copied and flipped to bottom half
+
:*6 = vertical mirroring, top half copied and flipped to bottom half
:* 7 = both mirroring, top left quarter copied and flipped to other quarters
+
:*7 = both mirroring, top left quarter copied and flipped to other quarters
  +
: The following modes have been added as of 0.2.0:
:* 65-71 = same as 1-7?
 
  +
:*129 = horizontal flip
The following modes have been added as of 0.2.0:
 
:* 129 = horizontal flip
+
:*130 = vertical flip
:* 130 = vertical flip
+
:*131 = both flip
:* 131 = both flip
 
 
:* 133 = clockwise 90 degree rotation
 
:* 133 = clockwise 90 degree rotation
 
:* 134 = 180 degree rotation (effectively equivalent to 131)
 
:* 134 = 180 degree rotation (effectively equivalent to 131)
:* 135 = counterclockwise 90 degree rotation
+
:*135 = counterclockwise 90 degree rotation
  +
:* 193-199 = same as 129-235?
 
  +
:Bit 6 (value 64) appears to be ignored.
   
 
'''0x5f2d / 24365'''
 
'''0x5f2d / 24365'''
  +
:If set to 1, devkit mode is enabled, allowing mouse coordinates and keyboard status to be checked via the [[Stat#.7B30.E2.80.A636.7D_Mouse_and_keyboard_in_.22devkit_mode.22|<code>stat()</code>]] command.
 
  +
:Controls devkit mode, a feature allowing mouse and keyboard status to be checked via the <code>[[Stat#.7B30.E2.80.A636.7D_Mouse_and_keyboard_in_.22devkit_mode.22|stat()]]</code> command. From the manual:
  +
<pre style="margin-left: 24px">
  +
POKE(0x5F2D, flags) -- where flags are:
  +
  +
0x1 Enable
  +
0x2 Mouse buttons trigger btn(4)..btn(6)
  +
0x4 Pointer lock (use stat 38..39 to read movements)
  +
</pre>
   
 
'''0x5f2e / 24366'''
 
'''0x5f2e / 24366'''
  +
:(undocumented, but confirmed by zep) If set to 1, causes the current palette scheme (see [[Pal|<code>pal()</code>]] and/or the 0x5f00-0x5f1f memory range, above) to persist instead of being reset at the end of the program.
 
  +
: If bit 0 (value 1) is set, causes the current palette scheme (see <code>[[Pal|pal()]]</code> and/or the 0x5f00..0x5f1f memory range, above) to persist instead of being reset at the end of the program.
  +
:If bit 1 (value 2) is set, causes the high-color mode configuration at 0x5f5f..0x5f7f to persist.
  +
: If bit 2 (value 4) is set, causes the audio effect switches at 0x5f40..0x5f43 to persist.
  +
:If bit 3 (value 8) is set, causes the read/write masks at 0x5f5e to persist.
  +
:If bit 4 (value 16) is set, causes the default print attributes at 0x5f58..0x5f5b to persist.
  +
:If bit 5 (value 32) is set, causes the fill pattern information at 0x5f31..0x5f33 to persist.
  +
:''(Other values are unverified in limited testing.)''
   
 
'''0x5f2f / 24367'''
 
'''0x5f2f / 24367'''
  +
:(undocumented) If set to 1, pause the music and SFX playback engine, until 0 is written back to it. If set to 2, allow music to continue when the pause menu is displayed.
 
  +
:(undocumented) If set to 1, pause the music and SFX playback engine, until 0 is written back to it. If set to 2, allow music and SFX to continue while the pause menu is being displayed.
   
 
'''0x5f30 / 24368'''
 
'''0x5f30 / 24368'''
  +
 
:(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:
 
:(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:
 
:<syntaxhighlight lang="lua">
 
:<syntaxhighlight lang="lua">
Line 232: Line 323:
 
</syntaxhighlight>
 
</syntaxhighlight>
   
'''0x5f31-0x5f33 / 24369-24371'''
+
'''0x5f31..0x5f33 / 24369..24371'''
  +
:Fill pattern ([[Fillp|<code>fillp()</code>]]). 0x5f31-0x5f32 contain the fill pattern as a 16-bit unsigned integer with the least significant byte first. 0x5f33's bit 0 is the related transparency bit.
 
  +
: Fill pattern (<code>[[Fillp|fillp()]]</code>). 0x5f31..0x5f32 contain the 16-bit fill pattern with the least-significant byte stored first.
  +
:0x5f33 contains the attribute flags for the fill pattern. Bit 0 (value 1) enables transparency, bit 1 (value 2) enables fill patterns for sprites, and bit 2 (value 4) enables other drawing functions that accept fill patterns to use the sprite fill pattern mechanism.
   
 
'''0x5f34 / 24372'''
 
'''0x5f34 / 24372'''
  +
:If set to 1, changes the PICO-8 drawing API to accept color values that incorporate not just one or two colors, but optionally include information about both the fill pattern and transparency right in the color value. From the manual:
 
  +
:If set to 1, changes the PICO-8 drawing API to accept color values that incorporate not just one or two colors, but optionally include information about the fill pattern right in the color value. From the manual:
 
<pre style="margin-left: 24px">
 
<pre style="margin-left: 24px">
 
-- bit 0x1000.0000 means the non-colour bits should be observed
 
-- bit 0x1000.0000 means the non-colour bits should be observed
-- bit 0x0100.0000 transparency bit
+
-- bit 0x0700.0000 0x1 transparency, 0x2 apply to sprites, 0x4 apply secondary palette
 
-- bits 0x00FF.0000 are the usual colour bits
 
-- bits 0x00FF.0000 are the usual colour bits
 
-- bits 0x0000.FFFF are interpreted as the fill pattern
 
-- bits 0x0000.FFFF are interpreted as the fill pattern
 
</pre>
 
</pre>
   
'''0x5f35-0x5f37 / 24373-24375'''
+
'''0x5f35 / 24373'''
:''(unknown, please update this if you know)''
 
   
  +
:Invalidates the endpoint of the previous line drawn using <code>[[Line|line()]]</code>, found in 0x5f3c..0x5f3f. When 0, the endpoint is valid. When 1, it's invalid, as if <code>line()</code> had been called with no arguments.
'''0x5f38 / 24376'''
 
:The width of the map area to sample with [[Tline|<code>tline()</code>]]. Coordinates will be calculated modulo this number to produce texture wrapping. It is expressed in map tiles (PICO8 manual still using the initial power of 2 revision).
 
   
  +
<span id="EnableUpperRAM"></span> <!-- insert a manual anchor since I think we're gonna end up linking people to this often enough -->
'''0x5f39 / 24377'''
 
  +
'''0x5f36 / 24374'''
:The height of the map area to sample with [[Tline|<code>tline()</code>]]. Coordinates will be calculated modulo this number to produce texture wrapping. It is expressed in map tiles.
 
   
  +
:Miscellaneous PICO-8 chipset features:
'''0x5f3a / 24378'''
 
:''(unknown, please update this if you know)''
 
   
  +
*If bit 2 (value 4) is set, automatic newlines are no longer added after each call to <code>[[Print|print()]]</code>. Also, due to a bug with PICO-8 printing escape codes, '\1' through '\6' will become printable if they are at the end of the string, but this should not be relied upon."
'''0x5f3b / 24379'''
 
:Invalidates the endpoint of the previous line drawn using [[Line|<code>line()</code>]], found in 0x5f3c-0x5f3f. When 0, the endpoint is valid. When 1, it's invalid, as if <code>line()</code> had been called with no arguments.
 
   
  +
*If bit 3 (value 8) is set, causes sprite 0 in <code>[[Map|map()]]</code> and <code>[[Tline|tline()]]</code> to be rendered as opaque (like other sprites) instead of the usual transparent.
'''0x5f3c-0x5f3f / 24380-24383'''
 
:Endpoint of the previous line drawn using [[Line|<code>line()</code>]]. The x and y coordinates are stored as 16-bit signed integers with the least significant byte first. These are only used if the byte at 0x5f3b is 0.
 
:: <code>0x5f3c-0x5f3d</code> / <code>24380-24381</code>: x coordinate
 
:: <code>0x5f3e-0x5f3f</code> / <code>24382-24383</code>: y coordinate
 
   
  +
*If bit 4 (value 16) is set, the upper 32 [[KiB]] bank of protected memory is switched out, and RAM is switched in, available for the application to write and read. See addresses '''0x8000..0xffff''' below for details.
== Hardware state ==
 
   
  +
'''0x5f37 / 24375'''
These memory addresses represent or control various aspects of the hardware. These are undocumented.
 
   
  +
:If set to 1, PICO-8 will not call <code>[[Reload|reload()]]</code> to copy cart ROM to RAM addresses 0x0000..0x42ff whenever exiting any editor mode. Normally this is done to update the expected copy of cart ROM in PICO-8 RAM. However, some carts make dynamic changes to this RAM at runtime, and this can be used to ensure those changes are preserved even if the cart is stopped and an editor is used before resuming. Note that <code>reload()</code> may still be used to copy ROM to RAM manually if necessary.
0x5f40-0x5f43 are control registers for the audio hardware. They're encoded with the following format:
 
   
  +
'''0x5f38...0x5f39 / 24376..24377'''
xxxx-ch3-ch2-ch1-ch0
 
   
  +
:The width and height of the map area to sample with <code>[[Tline|tline()]]</code>. Coordinates will be calculated modulo these numbers to produce texture wrapping. These normally should be a power of 2 to work as expected, but PICO-8 actually subtracts 1 from these before performing a bitwise AND on the offset into the map.
Setting bit 0 (ch0, value 1) enables the effect for channel 0, bit 1 (ch1, value 2) is for channel 1, etc. The "x" bits are unused. The features that each register control are as follows:
 
  +
  +
'''0x5f3a..0x5f3b / 24378..24379'''
  +
  +
:The X and Y offsets of the map area to sample with <code>[[Tline|tline()]]</code>. These are expressed in map tiles. These are applied after the texture wrapping.
  +
  +
'''0x5f3c..0x5f3f / 24380..24383'''
  +
  +
:Endpoint of the previous line drawn using <code>[[Line|line()]]</code>. The X and Y coordinates are stored as 16-bit signed integers with the least significant byte first. These are only used if the byte at 0x5f35 is 0.
  +
::<code>0x5f3c..0x5f3d</code> / <code>24380..24381</code>: x coordinate
  +
::<code>0x5f3e..0x5f3f</code> / <code>24382..24383</code>: y coordinate
  +
  +
==Hardware state==
  +
  +
These memory addresses represent or control various aspects of the hardware.
  +
  +
0x5f40..0x5f43 control various audio effects. They're encoded with the following format:
  +
  +
high3-high2-high1-high0-low3-low2-low1-low0
  +
  +
Setting bit 0 (value 1) enables a "low" effect for channel 0, bit 1 (value 2) for channel 1, etc.
  +
  +
Similarly, bit 4 (value 16) enables a "high" effect for channel 0, bit 5 (value 32) for channel 1, etc.
   
 
'''0x5f40 / 24384'''
 
'''0x5f40 / 24384'''
  +
:Halves an audio channel's clock rate. The main rate is 22.05 KHz, and enabling the feature for a channel will cause it to be 11.025 KHz instead. This causes SFX and arp speeds to be halved, and the note pitch to be an octave lower.
 
  +
:Low: Halves a channel's clock rate. The main sampling rate in PICO-8 is 22.05 KHz, and enabling the feature for a channel will cause it to be ''approximately'' 11.025 KHz instead. This causes SFX and arp speeds to be halved, and the note pitch to be effectively an octave lower.
  +
:High: Halves a channel's pitch. PICO-8 essentially just subtracts 12 from the note values played on the channel.
   
 
'''0x5f41 / 24385'''
 
'''0x5f41 / 24385'''
  +
:Enables reverb (echo) for a channel.
 
  +
: Low: Force-enables REVERB-2 for a channel. This has priority over high.
  +
:High: Enables REVERB-1 for a channel, unless REVERB-2 is specified in its currently-playing SFX/pattern.
   
 
'''0x5f42 / 24386'''
 
'''0x5f42 / 24386'''
  +
:Distorts the output of a channel. The audio becomes 3-bit (8 linear levels) without any dithering.
 
  +
:Low: Distorts the output of a channel (clamps the range of amplitude levels). This has priority over high.
  +
:High: An alternate distortion that's a bit louder.
   
 
'''0x5f43 / 24387'''
 
'''0x5f43 / 24387'''
:Enables a lowpass filter for a channel.
 
   
  +
:Low: Force-enables DAMPEN-2 for a channel.
:The priorities of the features are as follows, from left (lowest priority) to right (highest priority):
 
  +
:High: Enables DAMPEN-1 for a channel, unless DAMPEN-2 is specified in its currently-playing SFX/pattern.
  +
:Low + High: Force-enables an even stronger dampen level.
  +
:
  +
: Reverb is processed first, then Distortion, and Dampen. Half-Clock slows down all these filters alongside the actual waveform/effect generation.
   
  +
'''0x5f44..0x5f4b / 24388..24395'''
:Reverb < Distortion < Lowpass < Half-Clock
 
   
  +
:These 8 bytes mirror the internal state of the pseudo-random number generator that <code>[[Rnd|rnd()]]</code> uses to create random values. This memory range can be saved before calling <code>[[Srand|srand()]]</code> and <code>rnd()</code> and then restored to continue the original stream of random numbers. This can be useful for games which need separate random number streams so that one may be deterministic over time while another can be used arbitrarily. It is strongly suggested that this state only be saved and restored, but not created. Use <code>srand()</code> to create a good, stable randomizer state.
'''0x5f44-0x5f4b / 24388-24395'''
 
  +
: Every time <code>rnd()</code> is called, the RNG state is updated as follows:
:These 8 bytes mirror the internal state of the pseudo-random number generator that [[Rnd|<code>rnd()</code>]] uses to create random values. This memory range can be saved before calling [[Srand|<code>srand()</code>]] and <code>rnd()</code> and then restored to continue the original stream of random numbers. This can be useful for games which need separate random number streams so that one may be deterministic over time while another can be used arbitrarily. It is strongly suggested that this state only be saved and restored, but not created. Use <code>srand()</code> to create a good, stable randomizer state.
 
  +
:# The 16-bit words at 0x5f44 and 0x5f46 are swapped.
  +
:#The 32-bit word at 0x5f48 is added to the 32-bit word at 0x5f44.
  +
:#The 32-bit word at 0x5f44 is added to the 32-bit word at 0x5f48. The 2 add operations are performed with little-endian values (i.e. the least-significant byte comes first).
   
'''0x5f4c-0x5f5b / 24396-24411'''
+
'''0x5f4c..0x5f53 / 24396..24403'''
  +
:''(unknown, please update this if you know)''
 
  +
:These 8 bytes contain the current button state. 0x5f4c contains the button state for player 0, 0x5f4d for player 1, and so on up to player 7.
  +
:Each byte is a bitmask arranged like the output of <code>[[Btn|btn()]]</code> when called without arguments. Particularly, 0x5f4c is <code>btn() & 0x3f</code> and 0x5f4d is <code>(btn() >> 8) & 0x3f</code>. Note that PICO-8 doesn't modify bit 6 (value 64) or 7 (value 128) of these bytes. As a result, the state of the pause button can't be read from here.
  +
  +
'''0x5f54..0x5f57 / 24404..24407'''
  +
  +
:''(unknown, please update this if you know.)''
  +
  +
'''0x5f58..0x5f5b / 24408..24411'''
  +
  +
:(0.2.2+) Default attributes for <code>[[Print|print()]]</code>. From the manual:
  +
<pre style="margin-left: 24px; font-size: 95%;">
  +
Although attributes are reset every time print() is called, it is possible to set their default
  +
values by writing to memory addresses 0x5f58..0x5f5b.
  +
  +
0x5f58 // bitfield
  +
0x1 when set to 0x1, bits 1..7 are observed:
  +
0x2 padding
  +
0x4 wide
  +
0x8 tall
  +
0x10 solid background
  +
0x20 invert
  +
0x40 dotty
  +
0x80 use custom font
  +
  +
// e.g. poke(0x5f58, 0x1 | 0x2 | 0x4 | 0x8 | 0x20 | 0x40) -- pinball everywhere
  +
  +
0x5f59 char_w (low nibble), char_h (high)
  +
0x5f5a char_w2 (low nibble), tab_w (high)
  +
0x5f5b offset_x (low nibble), offset_y (high)
  +
  +
// any nibbles equal to 0 are ignored
  +
// tab_w values are mapped to 4..64
  +
</pre>
   
 
'''0x5f5c / 24412'''
 
'''0x5f5c / 24412'''
  +
:Auto-repeat delay for <code>btnp()</code>: When a button is held down, this controls the delay between the initial signal and the first auto-repeat signal. Expressed in 30ths of a second. The default value is 0, which tells PICO-8 to use the system delay setting. A value of 255 (or -1) disables the button repeat feature.
 
  +
: Auto-repeat delay for <code>btnp()</code>: When a button is held down, this controls the delay between the initial signal and the first auto-repeat signal. Expressed in 30ths of a second. The default value is 0, which tells PICO-8 to use the system delay setting. A value of 255 (or -1) disables the button repeat feature.
   
 
'''0x5f5d / 24413'''
 
'''0x5f5d / 24413'''
  +
 
:Auto-repeat interval for <code>btnp()</code>: When a button is held down, this controls the intervals between auto-repeat signals. Expressed in 30ths of a second. The default value is 0, which tells PICO-8 to use the system delay setting.
 
:Auto-repeat interval for <code>btnp()</code>: When a button is held down, this controls the intervals between auto-repeat signals. Expressed in 30ths of a second. The default value is 0, which tells PICO-8 to use the system delay setting.
   
 
'''0x5f5e / 24414'''
 
'''0x5f5e / 24414'''
:Bitmask for reading and writing colors. Allows PICO-8 to use only certain bits of the source color, and to write only certain bits of the destination color. If the lower four bits are nonzero, the 1 bits indicate which bits to set, while 0 bits indicate which bits to preserve. If the upper four bits are nonzero, the 1 bits indicate which source color bits to keep, and the 0 bits indicate which bits to discard. The default value is 0, which allows all bits to be read and written, as if the mask had been set to 0xff.
 
   
  +
:Allows PICO-8 to mask out certain bits of the input source color of drawing operations, and to write to specific [https://en.wikipedia.org/wiki/Bit_plane bitplanes] in the screen (there's 4 of them since PICO-8 uses a 4BPP display). Bits 0..3 indicate which bitplanes should be set to the new color value, while bits 4..7 indicate which input color bits to keep.
:This is effectively the pixel-writing operation:
 
  +
:For example, <code>poke(0x5f5e, 0b00110111)</code> will cause drawing operations to write to bitplanes 0, 1, and 2 only, with 0 and 1 receiving the color value bits, 2 being cleared, and 3 being unaltered.
:: <code>dst_color = (dst_color & ~write_mask) | (src_color & write_mask & read_mask)</code>
 
  +
:This formula is applied for every pixel written:
  +
::<code>dst_color = (dst_color & ~write_mask) | (src_color & write_mask & read_mask)</code>
   
'''0x5f5f-0x5f7f / 24415-24447'''
+
'''0x5f5f / 24415'''
:The remaining registers up to 0x5f7f are undocumented.
 
   
  +
:(Undocumented) Specifies a high-color mode (modes that allow for more than 16 colors on-screen on any given frame). Allows the usage of per-line palette swapping if set to 0x10, a 5-bitplane resolution-sacrificing screen if set to 0x20 (also requires 0x5f2c to be set to 1), or the usage of line-specific colors if set to 0x3''n'' (the ''n'' digit specifies the primary screen color to replace with horizontal bars of up to 16 colors). Other values are unknown, and PICO-8 appears to just operate in regular 16-color mode. None of these modes allow for any arbitrary 128x128 5BPP image to be displayed.
== GPIO pins ==
 
  +
:[https://www.lexaloffle.com/bbs/?tid=38565 See Bonevolt's BBS post for more in-depth information and examples.]
  +
  +
'''0x5f60..0x5f6f / 24416..24431'''
  +
  +
:(0.2.2+) 16-entry look-up table used for sprite fill patterns (<code>[[Pal|pal(...,2)]]</code>). Once the draw palette remapping is computed as normal, a byte is taken from this LUT. The lower nibble specifies the color for the "0" bits in the fill pattern, and the upper nibble for the "1" bits, just like with the pen colors at 0x5f25. This value is then AND'ed with the read-mask at 0x5f5e as usual.
  +
:(Undocumented) This is also a look-up table for the secondary display palette (modes 0x10 and 0x20) and the colors that make up mode 0x3n (the first color is for the top-most 128×8 section, the second for the 128×8 section underneath, etc.). The format of this section is identical to the screen palette in the '''Draw State''' section (see above).
  +
:Since this region is used for two independent features, the programmer must decide whether the sprite fill-pattern rendering or the selection of high-color modes is applicable.
  +
  +
'''0x5f70..0x5f7f / 24432..24447'''
  +
  +
:(Undocumented) A 1x128 bitfield that specifies which screen lines should use the secondary screen palette instead of the primary one in mode 0x10. Mode 0x20 instead swaps palettes on a pixel-by-pixel basis if a pixel in the hidden 64x128 half of the screen is not zero, thus, this section has an unknown or undefined purpose in that mode.
  +
:If mode 0x3n is used, these specify a +1 offset for the indexed secondary palette color on the given line (e.g. line 60 uses color 60 \ 8 = 7, setting the bit will cause it to be 8) with color 15 wrapping around to 0.
  +
:Each of these 16 bytes are for each 8-line section of the screen. Bit 0 contains the section's top-most line, while bit 7 contains its bottom-most line.
  +
:Note that the affected sections aren't limited to horizontal rows. The current screen transformation selected in '''0x5f2c''' happens after the high-color effect 0x10 or 0x3n takes place. If rotation modes 133 or 135 are used, this can allow those effects to be applied in vertical columns instead. Mode 0x20 requires the screen transformation mode to be 1, other modes such as 2 or 3 don't seem to be supported.
  +
  +
==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. JavaScript code that runs in a browser can also access them by defining a global array named ''pico8_gpio''. There are up to 128 pins, depending on the platform.
 
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. JavaScript code that runs in a browser can also access them by defining a global array named ''pico8_gpio''. There are up to 128 pins, depending on the platform.
   
'''0x5f80-0x5fff / 24448-24575'''
+
'''0x5f80..0x5fff / 24448..24575'''
:Each byte represents the value of 1 pin. The possible values vary depending on the platform.
 
   
  +
:Each byte represents the value of one pin. The possible values vary depending on the platform.
== Screen data ==
 
   
  +
==Screen data==
This 8,192-byte (8 [[KiB]]) 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 [[GameLoop|game loop]] or by a call to [[Flip|<code>flip()</code>]].
 
   
  +
This 8,192-byte (8 [[KiB]]) 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 [[GameLoop|game loop]] or by a call to <code>[[Flip|flip()]]</code>.
'''0x6000-0x7fff / 24576-32767'''
 
:All 128 rows of the screen, top to bottom. Each row contains 128 pixels in 64 bytes. Each byte contains two adjacent pixels, with the lo 4 bits being the left/even pixel and the hi 4 bits being the right/odd pixel.
 
   
  +
'''0x6000..0x7fff / 24576..32767'''
== Lua Memory ==
 
  +
  +
:All 128 rows of the screen, top to bottom. Each row contains 128 pixels in 64 bytes. Each byte contains two adjacent pixels, with the low 4 bits being the left/even pixel and the high 4 bits being the right/odd pixel.
  +
:This is essentially the same format as the sprite sheet at '''0x0000..0x1fff''' (see above). As a result, you can use <code>[[Memcpy|memcpy()]]</code> as a cheaper way to display the entire sprite sheet onto the screen, or vice versa.
  +
  +
==Upper memory==
  +
  +
'''0x8000..0xffff / 32768..65535 / -32768..-1 '''
  +
  +
This address range is considered to be where the program and kernel ROM would reside if this were not a virtual console. It is protected, so trying to <code>peek</code> or <code>poke</code> this area will produce errors.
  +
  +
(undocumented) If bit 4 of the hardware register at '''0x5f36 / 24374''' is set to 1 (e.g. "<code>poke(0x5f36,16)</code>"), a 32 [[KiB]] bank of user-accessible RAM is switched in. This may be accessed at addresses 0x8000..0xffff in hex, or -32768..-1 in PICO-8's decimal number system. It's also possible to write numeric literals for <code>[[Poke|poke()]]</code> or <code>[[Peek|peek()]]</code> as 32768..65535, which are technically outside of the PICO-8 number range, but which will be clipped to 16-bit values by the Lua parser, resulting in the range effectively representing -32768..-1. The choice of hex vs. signed vs. unsigned numeric literals is purely cosmetic in this case, e.g. <code>poke(-1,1)</code> is shorter than the equivalent <code>poke(65535,1)</code> or <code>poke(0xffff,1)</code>.
  +
  +
'''Warning:''' At the time of writing, switching this bank to RAM is a newly-discovered undocumented feature, and it is not yet known if there are any drawbacks. Quite often a discovery like this is followed by discovering a tradeoff, so be aware that there may be unknown caveats.
  +
  +
==Lua Memory==
 
The Memory used by Lua (global variables, local variables, tables, etc.) is entirely separate from the Pico-8 memory discussed above and is limited to 2 [[MiB]].
 
The Memory used by Lua (global variables, local variables, tables, etc.) is entirely separate from the Pico-8 memory discussed above and is limited to 2 [[MiB]].
   
The amount of memory currently used by the program can be checked with [[Stat|stat(0)]] and adds up as follows (all numbers are in bytes):
+
The amount of memory currently used by the program can be checked with <code>[[Stat|stat(0)]]</code> and adds up as follows (all numbers are in bytes):
  +
* '''nil / boolean / number''' - no extra cost.
 
  +
*'''nil / boolean / number''' - no extra cost.
* '''string''' - 17 + 1 * (# of characters)
 
  +
*'''string''' - 17 + 1 * (# of characters)
   
 
Strings of length <= 40 are always interned, meaning creating such a string again (through any means) will simply use the previously created string and cost nothing.
 
Strings of length <= 40 are always interned, meaning creating such a string again (through any means) will simply use the previously created string and cost nothing.
   
 
On the other hand, interned strings are also stored in a global hash table, which grows whenever the number of interned strings reaches a new power of 2. Here, each interned string costs an additional ~4-8 bytes, though this cost is only observable - in bulk - whenever the hash table grows.
 
On the other hand, interned strings are also stored in a global hash table, which grows whenever the number of interned strings reaches a new power of 2. Here, each interned string costs an additional ~4-8 bytes, though this cost is only observable - in bulk - whenever the hash table grows.
  +
* '''table''' - 32 + 8 * nextpow2(# of 'array' entries) + 20 * nextpow2(# of 'hash' entries)
 
  +
*'''table''' - 32 + 8 * nextpow2(# of 'array' entries) + 20 * nextpow2(# of 'hash' entries)
   
 
Here, nextpow2 gives the next power of 2 (e.g. 2 -> 2, 3 -> 4, 4 -> 4, 5 -> 8, 130 -> 256).
 
Here, nextpow2 gives the next power of 2 (e.g. 2 -> 2, 3 -> 4, 4 -> 4, 5 -> 8, 130 -> 256).
   
 
For example, {1,2,a=3,b=4,c=5} takes 128 bytes: 32 + 8 * 2 + 20 * 4
 
For example, {1,2,a=3,b=4,c=5} takes 128 bytes: 32 + 8 * 2 + 20 * 4
  +
* '''function '''- 16 + 4 * (# of captured variables) + 32 * (# of newly captured variables)
 
  +
*'''function '''- 16 + 4 * (# of captured variables) + 32 * (# of newly captured variables)
   
 
A captured variable is any local variable declared outside the function, that's accessed inside the function.
 
A captured variable is any local variable declared outside the function, that's accessed inside the function.
Line 349: Line 537:
   
 
If a function is created multiple times, the previously created instance is reused if possible, thus costing nothing. The previous instance can be reused if it has no captured variables, or if it has captured variables but they're all the same variables as the captured variables of the new function.
 
If a function is created multiple times, the previously created instance is reused if possible, thus costing nothing. The previous instance can be reused if it has no captured variables, or if it has captured variables but they're all the same variables as the captured variables of the new function.
  +
* '''thread''' (created by cocreate) - 352 bytes.
 
  +
*'''thread''' (created by cocreate) - 352 bytes.
  +
 
[[Category:Reference]]
 
[[Category:Reference]]

Revision as of 19:42, 27 July 2021

PICO-8 has 64 KiB of addressable memory, used for graphics, map, sound, music, and direct access to hardware features such as persistent cartridge data and GPIO pins. Normally only the lower 32 KiB are accessible, while the upper 32 KiB are protected, with the PICO-8 fantasy lore suggesting that the kernel and the game itself might reside there. However, it is possible to switch the upper 32 KiB to RAM. Programs can read from and write to this memory 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 KiB 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.

The cstore() function can be used to write memory data to the cartridge file. The reload() function can also be used 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 0x55ff General use (or work RAM)
0x5600 0x5dff General use / custom font (0.2.2+)
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 a 4-bit value, also known as a nybble. Thus, 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. Pixels are stored from left to right, top to bottom.

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.

0x0000..0x0fff / 0..4095

The upper 64 rows of pixels (that is, upper 8 rows of sprites) in the sprite sheet. Each 64-byte row contains 128 pixels. Each byte contains two adjacent pixels, with the low 4 bits being the left/even pixel and the high 4 bits being the right/odd pixel.

0x1000..0x1fff / 4096..8191

The lower 64 rows of pixels (that is, lower 8 rows of sprites) in the sprite sheet. Same format as above. Overlaps lower half of Map (see below).

If sp is the sprite number, then the memory address at which a sprite's data starts is given by the expression:

addr = 512 * (sp \ 16) + 4 * (sp % 16)

Explanation: think of the sprite sheet as a grid of 16x16 sprites. Then the high 4 bits of the sprite number (sp \ 16) indicates the row number (0-15), and the low 4 bits of the sprite number (sp % 16) indicates the column number (0-15). Every row of this grid is made up of 16 sprites, so each row occupies 16 sprites * 32 bytes/sprite = 512 bytes. This explains the 512 * (sp \ 16) part. After that, we have to locate it within the row. The column is sp % 16, and we have to walk forward 4 bytes for each sprite (8 pixels), so we have to move forward sp % 16 bytes.

The entire sprite is NOT stored at that position though, because the sprite sheet is a single image, you will only find, at that address, the 4 bytes (8 pixels) that correspond to the top row of the sprite. If you want the next row, you have to increment addr by 64 (that jumps over an entire row of 128 pixels = 64 bytes). In graphics parlance, the stride (amount you add to get from one row to the next in the image) is 64 bytes.

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.

The map is read from left to right, top to bottom order.

0x1000..0x1fff / 4096..8191

The lower 32 rows of the map. Each row contains 128 tiles. Each byte contains one tile index. Overlaps lower half of Sprite Sheet (see above).

0x2000..0x2fff / 8192..12287

The upper 32 rows of the map. Each row contains 128 tiles. Each byte contains one tile index.

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.

Note that the binary representation of the byte is reverse from the order of the flag buttons in the sprite editor. For example, if a sprite only has the orange and yellow flags set, the byte representing its flags will be 0b00000110.

0x3000..0x30ff / 12288..12543

Each byte represents the flags for the associated sprite.

Music

There are 64 music frames. Each frame (from 0 to 63) uses four consecutive bytes corresponding with the four PICO-8 sound channels, for a total of 256 bytes.

If bit 6 (value 64) is 0, then the corresponding channel is enabled with the sound ID specified by bits 5-0 (values 0 to 63). If bit 6 is 1, the channel is disabled with bits 5-0 being unused.

Bit 7 (value 128) does not have a function associated per-channel, but is used to describe the flags for the frame. The 1st byte of the frame is "begin loop." The 2nd byte is "end loop." The 3rd byte is "stop at end." Bit 7 in the 4th byte is either unknown or unused, so please update this section if you know its purpose.

Sound effects

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

The editor mode and filter switches can be decoded and assigned to Lua variables as follows:

-- compute address of sfx
sfxaddr = 0x3200 + sfxid*68

byte = @(sfxaddr+64)
editormode = byte&1 > 0 -- set to true if in tracker mode
noiz = byte&2 > 0
buzz = byte&4 > 0
detune = byte\8%3
reverb = byte\24%3
dampen = byte\72%3

They can also be encoded back as follows:

-- compute address of sfx
sfxaddr = 0x3200 + sfxid*68

byte = editormode and 1 or 0 -- set to 1 if in tracker mode
byte |= noiz and 2 or 0
byte |= buzz and 4 or 0
byte += detune * 8
byte += reverb * 24
byte += dampen * 72
poke(sfxaddr+64, byte)

The binary (2-level) switches are simply given their own bits, but the 3-level switches are stored in a way that allows all combinations of those (3 ^ 3 = 27) to be expressed within the remaining 5 of the available 8 bits. 5 bits allow for up to 32 possible values to be stored (0 to 31), so this decision was made.

The effect speed is a value between 0 and 255, representing the duration of each note in the effect, as a multiple of 183 ticks (with 22050 ticks in a second), approximately 1/120 of a second. A speed of 0 appears to be treated as 1. Using the full effect length of 32 notes, with a speed of 1, the full effect plays approximately 1/4 second (0.26557823129 seconds, or 32 * 183 / 22050). With a speed of 4, the full effect plays in 1.062 seconds.

In an effect used for a music pattern, beats per minute can be calculated 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/120 seconds per note, 15*4/120 seconds per four notes (one beat), (15*4)/(120*60) minutes per beat, or (120*60)/(15*4) = 120 beats per minute. (Note that we take 120 as an approximation of 22050/183 = 120.491803279)

Each note is encoded in 16 bits, in Little Endian style, with the low 8 bits in the first byte, and the high 8 bits in the second, formatted like so:

Second byte / High 8 bits
c e e e v v v w
First byte / Low 8 bits
w w p p p p p p
  • 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+)
  • eee: effect (0-7)
  • vvv: volume (0-7)
  • www: waveform (0-7)
  • pppppp: pitch (0-63)

General use

0x4300..0x55ff / 17152..22015

This memory region is available for the program to use for any purpose.

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

(Undocumented?) This region is not reset when loading another cart via load(), so can be used for passing data to and from the loaded cart.

General use / custom font

0x5600..0x5dff / 22016..24063

This memory region is available for the program to use for any purpose, like the 0x4300..0x55ff region above. Starting with version 0.2.2, this is also used for storing the custom font (use P8SCII code 14 to select this font, and 15 to return back to the default font).

There are 256 characters mapped to each of the 256 P8SCII codes. Each character consists of 8 bytes for each of its 8 rows of pixels, with the first byte being the top-most row, for a total of 2 KB (256 * 8 = 2048 bytes). Each byte consists of 8 pixels, with the left-most pixel in the LSB (bit 0, value 1), and the right-most pixel in the MSB (bit 7, value 128). This is reverse from the binary representation.

Since character 0 (null) is never drawn, its data in memory is purposed by PICO-8 to store default attributes for the font, which are all unsigned bytes:

0x5600 / 22016 - Character width (characters <128)

0x5601 / 22017 - Character width (characters >=128)

0x5602 / 22018 - Character height

0x5603 / 22019 - Draw X offset

0x5604 / 22020 - Draw Y offset

0x5605..0x5607 / 22021..22023 - (Unknown. Please document the significance of these bytes if you know.)

Persistent cart data

0x5e00..0x5eff / 24064..24319

After persistent data is initialized with the cartdata() function, the 256-byte region from 0x5e00 to 0x5eff represents the 64 number values accessible by dset() and dget(). These numbers are stored in the same 4-byte, little endian, 16.16 fixed-point format used by peek4() and poke4().

Note that using dset() and dget() partitions this memory into 64 standard PICO-8 numbers, but these are just helper functions and they are not mandatory. This memory region can be formatted in any desired manner. For instance, a bar chart with up to 51 bars could be encoded by saving a width for each bar and its color index, with the width being a full PICO-8 number and the color just being a byte:

function bar_set(index, width, color)
  local addr = 0x5e00 + index*5
  poke4(addr, width)
  poke(addr+4, color)
end

function bar_get(index)
  local addr = 0x5e00 + index*5
  return peek4(addr), peek(addr+4)
end

Draw state

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

0x5f00..0x5f0f / 24320..24335

Draw palette look-up table (pal(), palt()). When PICO-8 is asked to draw a certain 4-bit color index, it looks up the color's index in this table to decide which 4-bit color index it should be remapped with to eventually be written to screen memory. The 16 values in this table should have their lower nibble (bits 0-3) set to 0-15, to indicate which index is actually written to screen memory, while their upper nibble (bits 4-7) should be either zero for normal operation, or non-zero (i.e. the byte value is from 16 to 255) if the color index is to be transparent.

0x5f10..0x5f1f / 24336..24351

Screen palette look-up table (pal(...,1)). PICO-8 reads this table while converting the color indices in screen memory into system ("hardware") colors to be shown on its display. As of this writing, there are officially only 16 system colors available, whose values range from 0 to 15. However, an additional, but undocumented, 16 colors appear to be available at values from 128 to 143, and zep appears to be fine with us knowing this. Bits 4-6 (values 16, 32, 64) appear to be ignored.

0x5f20..0x5f23 / 24352..24355

Clipping rectangle (clip(x,y,w,h)):
  • 0x5f20 / 24352: x_begin (no pixels < x_begin will be drawn)
  • 0x5f21 / 24353: y_begin (no pixels < y_begin will be drawn)
  • 0x5f22 / 24354: x_end (no pixels >= x_end will be drawn)
  • 0x5f23 / 24355: y_end (no pixels >= y_end will be drawn)
If x_end is less than or equal to x_begin, or y_end is less than or equal to y_begin, then no visible clipping area is formed, effectively blocking rendering.
These are somewhat different from the clip(x,y,w,h) arguments. Use clip(xb,yb,xe-xb,ye-yb) to set a clip rectangle using values like these, or starting with 0.2.2, poke(0x5f20,xb,yb,xe,ye) to save tokens.
Note: clip() clamps the rectangle to the edges of the display. Expect x,y begin values to be in the range 0..127, and x,y end values to be in the slightly-larger range 0..128.

0x5f24 / 24356

(unknown, please update this if you know)

0x5f25 / 24357

Pen color (color()). The bottom 4 bits (0-3) are the current color index, from 0-15. The top 4 bits (4-7) are typically 0 and unused, but when using fill patterns, they will be the secondary color index.

0x5f26..0x5f27 / 24358..24359

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

0x5f28..0x5f2b / 24360..24363

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 / 24364

This value sets the screen transformation mode to be variations of stretching, mirroring, flipping, or rotating. This can't be changed in-between draw calls; it affects the entire screen.
  • 0 = normal mode
  • 1 = horizontal stretch, 64x128 screen, left half of normal screen
  • 2 = vertical stretch, 128x64 screen, top half of normal screen
  • 3 = both stretch, 64x64 screen, top left quarter of normal screen
  • 5 = horizontal mirroring, left half copied and flipped to right half
  • 6 = vertical mirroring, top half copied and flipped to bottom half
  • 7 = both mirroring, top left quarter copied and flipped to other quarters
The following modes have been added as of 0.2.0:
  • 129 = horizontal flip
  • 130 = vertical flip
  • 131 = both flip
  • 133 = clockwise 90 degree rotation
  • 134 = 180 degree rotation (effectively equivalent to 131)
  • 135 = counterclockwise 90 degree rotation
Bit 6 (value 64) appears to be ignored.

0x5f2d / 24365

Controls devkit mode, a feature allowing mouse and keyboard status to be checked via the stat() command. From the manual:
POKE(0x5F2D, flags)  -- where flags are:

		0x1 Enable
		0x2 Mouse buttons trigger btn(4)..btn(6)
		0x4 Pointer lock (use stat 38..39 to read movements)

0x5f2e / 24366

If bit 0 (value 1) is set, causes the current palette scheme (see pal() and/or the 0x5f00..0x5f1f memory range, above) to persist instead of being reset at the end of the program.
If bit 1 (value 2) is set, causes the high-color mode configuration at 0x5f5f..0x5f7f to persist.
If bit 2 (value 4) is set, causes the audio effect switches at 0x5f40..0x5f43 to persist.
If bit 3 (value 8) is set, causes the read/write masks at 0x5f5e to persist.
If bit 4 (value 16) is set, causes the default print attributes at 0x5f58..0x5f5b to persist.
If bit 5 (value 32) is set, causes the fill pattern information at 0x5f31..0x5f33 to persist.
(Other values are unverified in limited testing.)

0x5f2f / 24367

(undocumented) If set to 1, pause the music and SFX playback engine, until 0 is written back to it. If set to 2, allow music and SFX to continue while the pause menu is being displayed.

0x5f30 / 24368

(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(btn(6)) poke(0x5f30,1)

0x5f31..0x5f33 / 24369..24371

Fill pattern (fillp()). 0x5f31..0x5f32 contain the 16-bit fill pattern with the least-significant byte stored first.
0x5f33 contains the attribute flags for the fill pattern. Bit 0 (value 1) enables transparency, bit 1 (value 2) enables fill patterns for sprites, and bit 2 (value 4) enables other drawing functions that accept fill patterns to use the sprite fill pattern mechanism.

0x5f34 / 24372

If set to 1, changes the PICO-8 drawing API to accept color values that incorporate not just one or two colors, but optionally include information about the fill pattern right in the color value. From the manual:
-- bit  0x1000.0000 means the non-colour bits should be observed
-- bit  0x0700.0000 0x1 transparency, 0x2 apply to sprites, 0x4 apply secondary palette 
-- bits 0x00FF.0000 are the usual colour bits
-- bits 0x0000.FFFF are interpreted as the fill pattern

0x5f35 / 24373

Invalidates the endpoint of the previous line drawn using line(), found in 0x5f3c..0x5f3f. When 0, the endpoint is valid. When 1, it's invalid, as if line() had been called with no arguments.

0x5f36 / 24374

Miscellaneous PICO-8 chipset features:
  • If bit 2 (value 4) is set, automatic newlines are no longer added after each call to print(). Also, due to a bug with PICO-8 printing escape codes, '\1' through '\6' will become printable if they are at the end of the string, but this should not be relied upon."
  • If bit 3 (value 8) is set, causes sprite 0 in map() and tline() to be rendered as opaque (like other sprites) instead of the usual transparent.
  • If bit 4 (value 16) is set, the upper 32 KiB bank of protected memory is switched out, and RAM is switched in, available for the application to write and read. See addresses 0x8000..0xffff below for details.

0x5f37 / 24375

If set to 1, PICO-8 will not call reload() to copy cart ROM to RAM addresses 0x0000..0x42ff whenever exiting any editor mode. Normally this is done to update the expected copy of cart ROM in PICO-8 RAM. However, some carts make dynamic changes to this RAM at runtime, and this can be used to ensure those changes are preserved even if the cart is stopped and an editor is used before resuming. Note that reload() may still be used to copy ROM to RAM manually if necessary.

0x5f38...0x5f39 / 24376..24377

The width and height of the map area to sample with tline(). Coordinates will be calculated modulo these numbers to produce texture wrapping. These normally should be a power of 2 to work as expected, but PICO-8 actually subtracts 1 from these before performing a bitwise AND on the offset into the map.

0x5f3a..0x5f3b / 24378..24379

The X and Y offsets of the map area to sample with tline(). These are expressed in map tiles. These are applied after the texture wrapping.

0x5f3c..0x5f3f / 24380..24383

Endpoint of the previous line drawn using line(). The X and Y coordinates are stored as 16-bit signed integers with the least significant byte first. These are only used if the byte at 0x5f35 is 0.
0x5f3c..0x5f3d / 24380..24381: x coordinate
0x5f3e..0x5f3f / 24382..24383: y coordinate

Hardware state

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

0x5f40..0x5f43 control various audio effects. They're encoded with the following format:

high3-high2-high1-high0-low3-low2-low1-low0

Setting bit 0 (value 1) enables a "low" effect for channel 0, bit 1 (value 2) for channel 1, etc.

Similarly, bit 4 (value 16) enables a "high" effect for channel 0, bit 5 (value 32) for channel 1, etc.

0x5f40 / 24384

Low: Halves a channel's clock rate. The main sampling rate in PICO-8 is 22.05 KHz, and enabling the feature for a channel will cause it to be approximately 11.025 KHz instead. This causes SFX and arp speeds to be halved, and the note pitch to be effectively an octave lower.
High: Halves a channel's pitch. PICO-8 essentially just subtracts 12 from the note values played on the channel.

0x5f41 / 24385

Low: Force-enables REVERB-2 for a channel. This has priority over high.
High: Enables REVERB-1 for a channel, unless REVERB-2 is specified in its currently-playing SFX/pattern.

0x5f42 / 24386

Low: Distorts the output of a channel (clamps the range of amplitude levels). This has priority over high.
High: An alternate distortion that's a bit louder.

0x5f43 / 24387

Low: Force-enables DAMPEN-2 for a channel.
High: Enables DAMPEN-1 for a channel, unless DAMPEN-2 is specified in its currently-playing SFX/pattern.
Low + High: Force-enables an even stronger dampen level.
Reverb is processed first, then Distortion, and Dampen. Half-Clock slows down all these filters alongside the actual waveform/effect generation.

0x5f44..0x5f4b / 24388..24395

These 8 bytes mirror the internal state of the pseudo-random number generator that rnd() uses to create random values. This memory range can be saved before calling srand() and rnd() and then restored to continue the original stream of random numbers. This can be useful for games which need separate random number streams so that one may be deterministic over time while another can be used arbitrarily. It is strongly suggested that this state only be saved and restored, but not created. Use srand() to create a good, stable randomizer state.
Every time rnd() is called, the RNG state is updated as follows:
  1. The 16-bit words at 0x5f44 and 0x5f46 are swapped.
  2. The 32-bit word at 0x5f48 is added to the 32-bit word at 0x5f44.
  3. The 32-bit word at 0x5f44 is added to the 32-bit word at 0x5f48. The 2 add operations are performed with little-endian values (i.e. the least-significant byte comes first).

0x5f4c..0x5f53 / 24396..24403

These 8 bytes contain the current button state. 0x5f4c contains the button state for player 0, 0x5f4d for player 1, and so on up to player 7.
Each byte is a bitmask arranged like the output of btn() when called without arguments. Particularly, 0x5f4c is btn() & 0x3f and 0x5f4d is (btn() >> 8) & 0x3f. Note that PICO-8 doesn't modify bit 6 (value 64) or 7 (value 128) of these bytes. As a result, the state of the pause button can't be read from here.

0x5f54..0x5f57 / 24404..24407

(unknown, please update this if you know.)

0x5f58..0x5f5b / 24408..24411

(0.2.2+) Default attributes for print(). From the manual:
Although attributes are reset every time print() is called, it is possible to set their default
values by writing to memory addresses 0x5f58..0x5f5b.

0x5f58 // bitfield
	0x1  when set to 0x1, bits 1..7 are observed:
	0x2  padding
	0x4  wide
	0x8  tall
	0x10 solid background
	0x20 invert
	0x40 dotty
	0x80 use custom font

	// e.g. poke(0x5f58, 0x1 | 0x2 | 0x4 | 0x8 | 0x20 | 0x40)  -- pinball everywhere

0x5f59 char_w   (low nibble), char_h   (high)
0x5f5a char_w2  (low nibble), tab_w    (high)
0x5f5b offset_x (low nibble), offset_y (high)

// any nibbles equal to 0 are ignored
// tab_w values are mapped to 4..64

0x5f5c / 24412

Auto-repeat delay for btnp(): When a button is held down, this controls the delay between the initial signal and the first auto-repeat signal. Expressed in 30ths of a second. The default value is 0, which tells PICO-8 to use the system delay setting. A value of 255 (or -1) disables the button repeat feature.

0x5f5d / 24413

Auto-repeat interval for btnp(): When a button is held down, this controls the intervals between auto-repeat signals. Expressed in 30ths of a second. The default value is 0, which tells PICO-8 to use the system delay setting.

0x5f5e / 24414

Allows PICO-8 to mask out certain bits of the input source color of drawing operations, and to write to specific bitplanes in the screen (there's 4 of them since PICO-8 uses a 4BPP display). Bits 0..3 indicate which bitplanes should be set to the new color value, while bits 4..7 indicate which input color bits to keep.
For example, poke(0x5f5e, 0b00110111) will cause drawing operations to write to bitplanes 0, 1, and 2 only, with 0 and 1 receiving the color value bits, 2 being cleared, and 3 being unaltered.
This formula is applied for every pixel written:
dst_color = (dst_color & ~write_mask) | (src_color & write_mask & read_mask)

0x5f5f / 24415

(Undocumented) Specifies a high-color mode (modes that allow for more than 16 colors on-screen on any given frame). Allows the usage of per-line palette swapping if set to 0x10, a 5-bitplane resolution-sacrificing screen if set to 0x20 (also requires 0x5f2c to be set to 1), or the usage of line-specific colors if set to 0x3n (the n digit specifies the primary screen color to replace with horizontal bars of up to 16 colors). Other values are unknown, and PICO-8 appears to just operate in regular 16-color mode. None of these modes allow for any arbitrary 128x128 5BPP image to be displayed.
See Bonevolt's BBS post for more in-depth information and examples.

0x5f60..0x5f6f / 24416..24431

(0.2.2+) 16-entry look-up table used for sprite fill patterns (pal(...,2)). Once the draw palette remapping is computed as normal, a byte is taken from this LUT. The lower nibble specifies the color for the "0" bits in the fill pattern, and the upper nibble for the "1" bits, just like with the pen colors at 0x5f25. This value is then AND'ed with the read-mask at 0x5f5e as usual.
(Undocumented) This is also a look-up table for the secondary display palette (modes 0x10 and 0x20) and the colors that make up mode 0x3n (the first color is for the top-most 128×8 section, the second for the 128×8 section underneath, etc.). The format of this section is identical to the screen palette in the Draw State section (see above).
Since this region is used for two independent features, the programmer must decide whether the sprite fill-pattern rendering or the selection of high-color modes is applicable.

0x5f70..0x5f7f / 24432..24447

(Undocumented) A 1x128 bitfield that specifies which screen lines should use the secondary screen palette instead of the primary one in mode 0x10. Mode 0x20 instead swaps palettes on a pixel-by-pixel basis if a pixel in the hidden 64x128 half of the screen is not zero, thus, this section has an unknown or undefined purpose in that mode.
If mode 0x3n is used, these specify a +1 offset for the indexed secondary palette color on the given line (e.g. line 60 uses color 60 \ 8 = 7, setting the bit will cause it to be 8) with color 15 wrapping around to 0.
Each of these 16 bytes are for each 8-line section of the screen. Bit 0 contains the section's top-most line, while bit 7 contains its bottom-most line.
Note that the affected sections aren't limited to horizontal rows. The current screen transformation selected in 0x5f2c happens after the high-color effect 0x10 or 0x3n takes place. If rotation modes 133 or 135 are used, this can allow those effects to be applied in vertical columns instead. Mode 0x20 requires the screen transformation mode to be 1, other modes such as 2 or 3 don't seem to be supported.

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. JavaScript code that runs in a browser can also access them by defining a global array named pico8_gpio. There are up to 128 pins, depending on the platform.

0x5f80..0x5fff / 24448..24575

Each byte represents the value of one pin. The possible values vary depending on the platform.

Screen data

This 8,192-byte (8 KiB) 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().

0x6000..0x7fff / 24576..32767

All 128 rows of the screen, top to bottom. Each row contains 128 pixels in 64 bytes. Each byte contains two adjacent pixels, with the low 4 bits being the left/even pixel and the high 4 bits being the right/odd pixel.
This is essentially the same format as the sprite sheet at 0x0000..0x1fff (see above). As a result, you can use memcpy() as a cheaper way to display the entire sprite sheet onto the screen, or vice versa.

Upper memory

0x8000..0xffff / 32768..65535 / -32768..-1

This address range is considered to be where the program and kernel ROM would reside if this were not a virtual console. It is protected, so trying to peek or poke this area will produce errors.

(undocumented) If bit 4 of the hardware register at 0x5f36 / 24374 is set to 1 (e.g. "poke(0x5f36,16)"), a 32 KiB bank of user-accessible RAM is switched in. This may be accessed at addresses 0x8000..0xffff in hex, or -32768..-1 in PICO-8's decimal number system. It's also possible to write numeric literals for poke() or peek() as 32768..65535, which are technically outside of the PICO-8 number range, but which will be clipped to 16-bit values by the Lua parser, resulting in the range effectively representing -32768..-1. The choice of hex vs. signed vs. unsigned numeric literals is purely cosmetic in this case, e.g. poke(-1,1) is shorter than the equivalent poke(65535,1) or poke(0xffff,1).

Warning: At the time of writing, switching this bank to RAM is a newly-discovered undocumented feature, and it is not yet known if there are any drawbacks. Quite often a discovery like this is followed by discovering a tradeoff, so be aware that there may be unknown caveats.

Lua Memory

The Memory used by Lua (global variables, local variables, tables, etc.) is entirely separate from the Pico-8 memory discussed above and is limited to 2 MiB.

The amount of memory currently used by the program can be checked with stat(0) and adds up as follows (all numbers are in bytes):

  • nil / boolean / number - no extra cost.
  • string - 17 + 1 * (# of characters)

Strings of length <= 40 are always interned, meaning creating such a string again (through any means) will simply use the previously created string and cost nothing.

On the other hand, interned strings are also stored in a global hash table, which grows whenever the number of interned strings reaches a new power of 2. Here, each interned string costs an additional ~4-8 bytes, though this cost is only observable - in bulk - whenever the hash table grows.

  • table - 32 + 8 * nextpow2(# of 'array' entries) + 20 * nextpow2(# of 'hash' entries)

Here, nextpow2 gives the next power of 2 (e.g. 2 -> 2, 3 -> 4, 4 -> 4, 5 -> 8, 130 -> 256).

For example, {1,2,a=3,b=4,c=5} takes 128 bytes: 32 + 8 * 2 + 20 * 4

  • function - 16 + 4 * (# of captured variables) + 32 * (# of newly captured variables)

A captured variable is any local variable declared outside the function, that's accessed inside the function.

A "newly" captured variable is merely one that wasn't captured before by other functions.

A function that uses any globals automatically captures _ENV, and this counts as a captured variable. (Unless _ENV is explicitly re-declared, it never counts as a newly captured variable, though.)

If a function is created multiple times, the previously created instance is reused if possible, thus costing nothing. The previous instance can be reused if it has no captured variables, or if it has captured variables but they're all the same variables as the captured variables of the new function.

  • thread (created by cocreate) - 352 bytes.