SNES-Dev Page-Table Format
Devices
The devices recognized by this format are as follows, and have the following properties:
DevNo |
Name |
Properties</th>
</tr>
|
0 |
ROM |
r+cp |
1 |
WRAM |
rw+zc |
2 |
P-RAM |
rw+cp |
4 |
Ex Registers |
rw+v |
5 |
Zeros |
rd+z |
6 |
Swap Rom |
rw+m0s |
7 |
PTROM |
r+cp |
8 |
expt reg |
rw+v |
</table>
Additional devices may be added at the option of the dynamic pager. A Dynamic pager should document additional devices which they support, and the properties of such devices. Up to 7 additional devices may be supported (device numbers 9-15).
### Device and Page Properties
Key:
* r: Device can be read
* w: Device can be written. If a device or page
* d: Writes to Device are dropped to no effect
* c: Device can be read and write cached. Mutually exclusive with *v*
* z: Device contains 0 bytes until first write to a particular address resolves.
* s: Writes to Device are dropped and instead index the swap table for the page, switching the page to the appropriate index. If extended swap is not enabled, 2-byte stores are truncated to the 8 least-signficant bits.
* m*n*: Device contains the same sequence of bytes as device *n* until first write to a particular address resolves.
* v: Device is volatile and cannot be cached. Mutually exclusive with *c*.
* p: Device is persistent and it is always valid.
A read to a byte of a page that is none of *p*, *v*, *z*, nor is mirroring such a page loads an indeterminate value.
If a byte of a mirrored page is written to before the equivalent byte in the mirroing page is written, reading that loads an indeterminite value.
If write to a page or device that is not marked as *w* is resolved, the effects are undefined. However the write MUST NOT be carried through to the underlying physical device.
A page which is marked as neither *c* nor *v*, preserves the cache setting of the underlying device. A device which is marked as neither *c* nor *v* has an unspecified cache setting. In particular, the device may be volatile. The cache setting is not required to be reported. Note that a cache setting of *c* does not mean that the device or page IS read/write cached. It simply says that it can be.
The properties for a device *n* can be queried using extended register 2100+2*n.
If the register is clear, then the device is not accessible
* 0x0001 indicates *r* property
* 0x0002 indicates *w* property
* 0x0004 indicates *d* property
* 0x0006 indicates *s* property
* 0x0008 indicates *v* property
* 0x0010 indicates *z* property
* 0x0020 indicates *c* property
* 0x0040 indicates *p* property
* 0x0*n*00 indicates m*n* property
## Format
A Snes-Dev Page Table can be represented as the following structure:
```
struct page_table{
pthead header;
pageinfo pages;
swapinfo swaps;
};
```
The Header is structured as follows:
```
struct pthead{
u8 magic[4];
version ver;
u8 pt_flags;
u8 pt_page_len;
u16 pt_ex_flags_or_reserved;
u16 pt_label;
u16 pt_checksum;
};
```
`magic` MUST be the byte sequence `[00 70 74 FF]`. `pt_label` may be 2 bytes. `pt_checksum` is the Internet Checksum of the header, which is described in [[RFC 1071]](https://tools.ietf.org/html/rfc1071). Whenever computing the checksum field of a structure, that checksum MUST be computed as though the checksum field is 0.
`ver` encodes the version of the SNES-Dev Page Table Specification which the file was created in.
This is encoded in the LCLib Versioning format, where the major value indicates the major version-1, and the minor value indicates the minor version.
The current version of the specification is 1.0, and therefore the version for a file created in this version is [00 00].
`pt_flags` indicates the page table flags. If bit 0x80 is set, this indicates extended page tables are requested, and `pt_ex_flags` are additionally used. If bit 0x01 is set, this page table requests the ability to define cloned segments. If bit 0x02 is set, this page table requests access to the ptrom in device 7. If bit 0x04 is set, this page table requests access to zero-assign pages, causing there initial value to be a stream of zero bytes. If bit 0x08 is set, then pages allocated in the table as both writable and executable are permitted. All other bits are reserved, and MUST be 0.
`pt_ex_flags_or_reserved` MUST be 0 unless bit 0x80 of `pt_flags` is set. Otherwise, if bit 0x8000 is set, then swappable pages are requested.
If bit 0x4000 is set in conjunction with bit 0x8000 then extended swappable pages are requested.
If bit 0x4000 MUST not be set on its own.
If bit 0x80 is set, then paging registers SHOULD made available in device 8, if not set or is unavailable, device 8 SHOULD be bound to a rw device that reads 0 bits, and drops all writes without error. This can allow the page table to be mutated by the process. All other bits are reserved, and MUST be 0.
Extended features which are available and enabled can be queried using extended register 2124 (available on device 4).
A bit in extended register 2124 MUST be set if the dynamic pager provides the feature and the feature is requested, but is not required to be clear if the feature is not requested. It MUST NOT be set if the feature is not available. (Implementation Note: A valid dynamic pager could track this internally as a read-only bitmask, and expose that bitmask anded with `pt_ex_flags` as extended register 2124).
`pt_page_len` refers to the length mode of the page table, given the following mappings:
* 0 is the smallest, 256-byte pages. There are a total of 65536 pages in this mode. The page base mask is 0xffff00. The suffix length is 8.
* 1 is 1024-byte pages. There are a total of 16384 pages in this mode. The page base mask is 0xfffc00. The suffix length is 10.
* 2 is 4096-byte pages. There are a total of 4096 pages in this mode. The page base mask is 0xfff000. The suffix length is 12.
* 3 is 16384-byte pages. There are a total of 1024 pages in this mode. The page base mask is 0xffc000. The suffix length is 14.
* 4 is 32768-byte pages. There are a total of 512 pages in this mode. The page base mask is 0xff8000. The suffix length is 15.
* 5 is 65536-byte pages. There are a total of 256 pages in this mode. The suffix length is 16.
The pageinfo structure is defined as follows
```
struct pageinfo{
u8 page_length;
union page pages[see below];
};
```
`page_length` is the sizs of the `page` union, in bytes. This MUST be 32.
The length of the pages array is the number of pages indicated by current page length mode. These are assigned in order. The nth page in the array has n<<s as its page base address, where s is the suffix length of the page length mode.
```
union page{
proc_reg_page process_registers;
unmapped_page unmapped_page;
device_page page;
};
```
Where:
```
struct proc_reg_page{
u8 page_type;
u8 __reserved[29];
u16 checksum;
};
```
```
struct unmapped_page{
u8 page_type;
u8 __reserved[29];
u16 checksum;
};
```
```
struct device_page{
u8 page_type;
u8 devno;
u16 properties;
u32 dev_page;
u32 mirror_offset_or_reserved;
u8 swap_ref_or_reserved;
u8 __reserved0;
u16 __reserved[7];
u16 checksum;
};
```
`__reserved` and `__reserved0` MUST always be 0. `checksum` is the internet checksum of the page structure with `checksum`.
`page_type` shall be:
* 0 for unmapped page
* 1 for processor register page
* 2 for device page
If swappable pages are on, and the page has the *s* property, the `dev_page` is ignored, but SHOULD be the same as swap-page 0 in the referenced swap page. `swap_ref_or_reserved` is the swap page used by this page.
If swappable pages are not requested, or the page does not have the *s* property, `swap_ref_or_reserved` MUST be set to 0. If swappable pages are requested, and the page has the *s* property, but swappable pages are not on, then `swap_ref_or_reserved` may be any sequence of bytes.
`properties` are handled the same was as device properties. Page Properties apply before device properties (so an *s* or *d* page can have *w*, even if the underlying device has *w*. Additionally an *s* or *d* page never causes writes to the underlying device. The exception is that a *v* or *p* device will take precedence over *z* or m*n* page).
If `properties` indicates a mirror page, then
When swap pages are disabled, `swapinfo` is ignored. Otherwise, if only standard swap pages are requested `swapinfo` has the following structure:
```
struct swapinfo{
u16 numSwapRef;
struct swap{
u8 numSwaps;
u8 __reserved;
u32 swapPages[numSwaps];
u16 checksum;
} swapRefs[numSwapRefs];
};
```
If extended pages are requested (even if they are not enabled), then `numSwaps` is a `u16` and `__reserved` is not part of the `swap` structure.
`checksum` is the internet checksum of the swap ref.