During startup, runtime, and shutdown, both the Host (Pocket) and Target (Core) need the ability to issue and respond to commands.
Commands are handled over the BRIDGE bus, and the 0xF8xxxxxx
region in its address space is reserved.
There are effectively two separate command/response systems. Host can send commands and poll for a response and Target can send commands and wait for a response.
Base address: 0xF8000000
Implementation of the command system register space can be done either with a couple block rams and a softcore CPU/state machine or just a handful of fabric registers and a FSM.
Commands may require additional parameter data. The target will provide pointers to where it wants the host to write this data when sending a command. The same goes for response data and finally again in both directions Host > Target and Target > Host.
The second and third columns denote whether the register can be read or written by the (H)ost or (T)arget.
0x00R: H, T
W: H, T
Host (Pocket > Core) command/status.
[31:16] 0x434D 'CM'
[15: 0] command word
Pocket writes here to execute a command. Just before, Pocket checks 0x4 to see where it should write any additional parameters, if applicable.
[31:16] 0x4255 'BU'
[15: 0] busy status
Core traps the write and updates the status. Pocket sees this flag and knows it's in progress. Status/progress information may be encoded in the lower 16 bits, such as a percentage.
[31:16] 0x4F4B 'OK'
[15: 0] result code
Core updates with result code. Exact result code depends on the command. Additional data must be encoded in a response format.
R: H
W: T
Host (Pocket > Core) parameter data pointer.
[31:0]
Address to put applicable parameter data. May be within this bram, or anywhere in the bridge address space. Must have enough room for the longest parameter list.
R: H
W: T
Host (Pocket > Core) response data pointer.
[31:0]
Address to put applicable response data. May be within this bram, or anywhere in the bridge address space. Pocket will read this address to find where to read a command response from the core.
0x1000R: H, T
W: H, T
Target (Core > Pocket) command/status.
[31:16] 0x636D 'cm'
[15: 0] command word
Core writes here to request command execution. Pocket polls and sees flag set
[31:16] 0x6275 'bu'
[15: 0] busy status
Pocket starts execution, updating status. Core watches this flag for progress. Status/progress information may be encoded in the lower 16 bits, such as a percentage.
[31:16] 0x6F6B 'ok'
[15: 0] result code
Pocket updates with result code. Additional data must be encoded in a response format.
R: H
W: T
Target (Core > Pocket) parameter data pointer. [31:0]
Address to put applicable parameter data. May be within this bram, or anywhere in the bridge address space. Must have enough room for the longest parameter list.
R: H
W: T
Target (Core > Pocket) response data pointer. [31:0]
Address to put applicable response data. May be within this bram, or anywhere in the bridge address space. Must have enough room for the longest parameter list.
R: H, T
W: H, T
Data slot size table. Word0: [15:0]
ID of the data slot Word1: [31:0]
Size of the data slot. Zero if the slot is not used. Repeat these 8 bytes for all 32 possible slots. When core is loaded, Pocket will write the filesize as loaded. Core may update the value during setup, idle, or run. Pocket will read the value back during a flush operation and update the filesize on SD if it changed.
R: H
W: -
Build date and version information.
APF has a Tcl script to populate this area of the bram on compile to include the build date/time, as well as a 32bit randomized ID to identify the build.
[31:0] Build Date in BCD, e.g. 0x20220531 (2022-May-31)
[31:0] Build Time in BCD, e.g. 0x00231159 (23:11:59)
[31:0] Build Unique ID
Part of the address space is reserved for a 32-entry table. In the example implementations this is a small block ram.
Each item contains two 32-bit words describing the 16-bit ID of that data slot corresponding to the Core Definition JSON, and the size in bytes of that slot.
While the core runs it may read this table to know how large of an asset was loaded, or in the case of a nonvolatile data slot (save file), it may write a revised size in case it changed.
If the data slot in question is marked with deferload
, the size and ID will still be written even though the file data itself will not be automatically loaded.
If the data slot in question has a file size exceeding 4 gigabytes, then 48-bit addressing will be used. The upper 16 bits will be packed in the unused space of the first word. For example:
Word 0 [31:16] Size (upper 16 bits)
Word 0 [15:0] ID
Word 1 [31:0] Size (lower 32 bits)
There will not be any impact if the file size is smaller than 4 gigabytes, as the extra addressing bits will simply be zero.
Request Status
Parameters: 0
Response: 0
Result Codes:
0x00
: Undefined0x01
: booting (Core clocks/FSM starting, PLL initialization)0x02
: setup (Pocket loads assets, core may request dataslot reads)0x03
: idle (held in reset, not executing)0x04
: runningReset Enter
Parameters: 0
Response: 0
Result Codes: -
Reset Exit
Parameters: 0
Response: 0
Result Codes: -
Data slot request read
Parameters: 1
[15:0]
Slot id (0-65535)Response: 0
Result Codes:
0
: ready to read1
: not allowed ever2
: check laterData slot request write
Parameters: 2
[31:16]
Expected size in bytes (upper 16 bits)[15:0]
Slot id (0-65535)[31:0]
Expected size in bytes (lower 32 bits)Response: 0
Result Codes:
0
: ready to write1
: not allowed ever2
: check laterData slot update
Parameters: 2
[15:0]
Slot id (0-65535)[31:0]
Expected size in bytesResponse: 0
Result Codes: 0
Data slot access all complete
Parameters: 0
Response: 0
Result Codes:
0
: okReal-time Clock Data
Parameters: 3
[31:0]
Unsigned uint32_t of seconds elapsed since the epoch of 1970.[31:0]
BCD of current date - example 0x20221031
[31:0]
BCD of current time - example 0x00235959
[27:24]
day of week, from 0 to 6[23:0]
BCD of current time - example 0x235959
Response: 0
Pocket sends this command during core boot once, with the current time. It is not continuously sent/updated.
Savestate: Start/Query
Parameters: 1
[0]
Request start. If not set, simply gives the below result without creating the state.
Response: 3
[0]
Set if savestate can be/was created[31:0]
Address of savestate blob when ready.[31:0]
Size of savestate blob when ready.
Result Codes:
0
: ok, no operation1
: busy creating blob2
: done, blob is ready3
: error, failedSavestate: Load/Query
Parameters: 1
[0]
Request load. If not set, simply gives the below result without loading the state.
Response: 3
[0]
Set if savestate can be/was loaded[31:0]
Address of where savestate blob should be written.[31:0]
Maximum size of savestate blob to be written.
Result Codes:
0
: ok, no operation1
: busy creating blob2
: done, blob is ready3
: error, failedOS Notify: Menu State
Parameters: 1
[0]
If set, user is in the OS menus and the core has lost focus.Response: 0
Result Codes:
Pocket sends this command during core operation as the user enters and exits the menu. To maintain compatibility, the command may be ignored by the core.
OS Notify: Cartridge Adapter
Parameters: 1
[24]
User selected ‘Play Cartridge’[16]
If cart power will be turned on immediately after reset exit[7:0]
Value of the detected cartridge adapter during boot.Response: 0
Result Codes:
Pocket sends this command during the core bootup to let the core know which cartridge adapter a user may have plugged in. Valid values are from 0x01
to 0x04
.
Intended for use when core.json's cartridge_adapter
checks are enabled, but will always be sent.
In this way, a core could optionally take advantage of at least one types of adapter(s) if one exists.
OS Notify: Docked State
Parameters: 1
[0]
If set, Pocket is inserted into DockResponse: 0
Result Codes:
Pocket sends this command during core operation as the user inserts and removes Pocket from Dock.
OS Notify: Display Mode
Parameters: 1
[15:8]
Display mode ID [0]
Core should output grayscale onlyResponse: 1
[15:0]
Response code to affirm core has switched to grayscale video output.Result Codes:
Pocket sends this command each time the user selects a new Display Mode. Some modes (LCD) mandate the core produce only grayscale video output. In that case, parameter bit 0 will be set, and the core must have a response word of 16’h444D
to allow that particular display mode to be used. See the video.json page.
Ready to run.
Parameters: 0
Response: 0
Result Codes: -
Debug Event Log.
Parameters: 1
[31:0]
Custom event ID to print in Debug Log
Response: 0
Result Codes: -
Data slot read.
Parameters: 4
[15:0]
Slot id (0-65535).
[31:0]
Slot offset
[31:0]
BRIDGE address
[31:0]
Length
Response: 0
Result Codes:
0
: all bytes read ok1
: slot not defined2
: error or out of range. If length is 0xFFFFFFFF
, the length will be sized to maximum legal valueData slot read (48-bit)
Parameters: 4
[31:16]
Slot offset (upper 16 bits)
[15:0]
Slot id (0-65535)
[31:0]
Slot offset (lower 32 bits)
[31:0]
BRIDGE address
[31:0]
Length
Response: 0
Result Codes:
0
: all bytes read ok 1
: slot not defined2
: error or out of range. If length is 0xFFFFFFFF
, the length will be sized to maximum legal valueData slot write.
Parameters: 4
[15:0]
Slot id (0-65535).
[31:0]
Slot offset
[31:0]
BRIDGE address
[31:0]
Length
Response: 0
Result Codes:
0
: all bytes written ok1
: slot not defined2
: error or out of range. If length is 0xFFFFFFFF
, the length will be sized to maximum legal valueData slot write (48-bit)
Parameters: 4
[31:16]
Slot offset (upper 16 bits)
[15:0]
Slot id (0-65535)
[31:0]
Slot offset (lower 32 bits)
[31:0]
BRIDGE address
[31:0]
Length
Response: 0
Result Codes:
0
: all bytes written ok 1
: slot not defined2
: error or out of range If length is 0xFFFFFFFF
, the length will be sized to maximum legal valueData slot flush
Parameters: 1
[15:0]
Slot id (0-65535)
Response: 0
Result Codes:
0
: all bytes written ok1
: slot not definedGet filename of data slot
Parameters: 2
[15:0]
Slot id (0-65535)
[31:0]
Pointer to get_dataslot_file_t
struct
Response: 0
Struct written by Host before command completion
Result Codes:
0
: ok1
: slot not definedOpen new file into data slot
Parameters: 2
[15:0]
Slot id (0-65535)
[31:0]
Pointer to get_dataslot_file_t
struct
Response: 0
Struct read by Host on command start
Result Codes:
0
: opened ok1
: created and opened ok (no error)2
: slot not defined3
: file not found4
: malformed path5
: general errorget_dataslot_file_t
Byte Offset: 0x0
Length: 256
Name: Full path including filename
Null-terminated string of the path and file selected for a given slot.
For example, the filename could include additional subdirectories: /Assets/abcd/common/directory1/data.bin
open_dataslot_file_t
Byte Offset: 0x0
Length: 256
Name: Full path including filename
Null-terminated string of the full path and file. The file can be in the Assets folder or the Saves folder, in any of the platforms supported by the core (if the data slot was not marked as core-specific).
For example, a data slot not marked as “core-specific”, belonging to the “abcd” platform, with the relative path directory1/data.bin
would be: /Assets/abcd/common/directory1/data.bin
If the core also supported the “xyz” platform, the following would also be valid: /Saves/xyz/common/directory1/save.bin
Byte Offset: 0x100
Length: 4
Name: Operation flags
Bit 0: Create if it doesn’t exist (slot must not be read-only).
Bit 1: Resize/truncate the file (slot must not be read-only).
Bits 2-31: Reserved, must be 0.
Byte Offset: 0x104
Length: 4
Name: Desired file size
Size to resize/truncate the file to, if flagged.
Target slot read/write commands are provided to allow working with much larger files - up to 4GByte in size. They should be used with data slots marked with deferload
set. In this case, APF will not load the file itself, but will still update the Dataslot ID/Size table with the file size.
Additionally, if the data slot is marked with the “User Reloadable” bit set in its Parameters Bitmap, APF will allow choosing a new file in the Interact menu, like any other. However, APF will handle this differently - instead of sending [0082 Data slot request write]
and then [008F Data slot access all complete]
, APF will only send [008A Data slot updated]
and update the Dataslot ID/Size table with the new information.
A core can retrieve the full path information for a file currently loaded in a data slot via the [0190 Get filename of data slot]
command. The core should supply a pointer to where APF will write the resulting filename. A core could use this path and filename information to request additional files by using [0192 Open new file into data slot]
. New files can also be created, or resized. Only assets or saves may be opened, and within platform folders that are supported in core.json
. A data slot must not be marked as read-only for a file to be modified. Once opened, the data slot can be read/written using other Target commands.