|
|
| (94 intermediate revisions by the same user not shown) |
| Line 1: |
Line 1: |
| − | {{WARNING|This page is still in the proposal stage and should not yet be considered an official specification.}}
| + | #REDICT [[NEO mapper/Extension]] |
| − | | |
| − | Proposal for an extension to the [[NEO mapper]] format.
| |
| − | | |
| − | == Specifications ==
| |
| − | | |
| − | === Principles ===
| |
| − | | |
| − | Any write operation to the NEO mapper with address bits 10-12 set to 0 is considered as access to extended features. In that case, the mapper bank register is not modified.
| |
| − | | |
| − | All other write operations should be considered normal access to the mapper's bank register.
| |
| − | | |
| − | The address contains an 8-bit function ID, and a 3-bit destination bank value for function to be applied to a given mapper's bank.
| |
| − | | |
| − | {|
| |
| − | |-
| |
| − | |
| |
| − | {| class="wikitable"
| |
| − | |+ ADDRESS
| |
| − | |-
| |
| − | ! 15 || 14 || 13 || 12 || 11 || 10 || 9 || 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
| |
| − | |-
| |
| − | |style="background-color:#BBB;" colspan="2"| Page
| |
| − | |style="background-color:#FAA;"| 0
| |
| − | |style="background-color:#FAA;"| 0
| |
| − | |style="background-color:#FAA;"| 0
| |
| − | |style="background-color:#AAF;" colspan="3"| Bank
| |
| − | |style="background-color:#AAF;" colspan="8"| Function
| |
| − | |}
| |
| − | |
| |
| − | {| class="wikitable"
| |
| − | |+ DATA
| |
| − | |-
| |
| − | ! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
| |
| − | |-
| |
| − | |style="background-color:#AAF;" colspan="8"| Parameter
| |
| − | |}
| |
| − | |}
| |
| − | | |
| − | === Functions ===
| |
| − | ==== 0x00: ROM mapper ====
| |
| − | Activate access to the cartridge ROM mapper through the given bank (default mode)
| |
| − | | |
| − | Parameter:
| |
| − | {| class="wikitable"
| |
| − | ! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
| |
| − | |-
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |}
| |
| − | | |
| − | ==== 0x01: Cartridge information ====
| |
| − | Activate read access to the cartridge information data through the given bank (8 KB mirrored on NEO-16)
| |
| − | | |
| − | Parameter:
| |
| − | {| class="wikitable"
| |
| − | ! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
| |
| − | |-
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |}
| |
| − | | |
| − | ==== 0x02: ''Reserved'' ====
| |
| − | | |
| − | ==== 0x03: RAM ====
| |
| − | Activate read/write access to RAM through the given bank
| |
| − | | |
| − | Parameter:
| |
| − | {| class="wikitable"
| |
| − | ! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
| |
| − | |-
| |
| − | |style="background-color:#AAF;" colspan="8"| RAM segment
| |
| − | |}
| |
| − | | |
| − | ==== 0x04: SRAM/FRAM ====
| |
| − | Activate read/write access to SRAM/FRAM through the given bank (8 KB mirrored on NEO-16)
| |
| − | | |
| − | Parameter:
| |
| − | {| class="wikitable"
| |
| − | ! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
| |
| − | |-
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#AAF;" colspan="4"| Segment
| |
| − | |}
| |
| − | | |
| − | ==== 0x05: ''Reserved'' ====
| |
| − | | |
| − | ==== 0x06: ''Reserved'' ====
| |
| − | | |
| − | ==== 0x07: SCC/SCC+ ====
| |
| − | Activate SCC to be accessed through memory area from 9800h to 9FFFh (4 KB mirrored)
| |
| − | Any bank number is valid, but bank #4 is recommanded for NEO-8 and #2 for NEO-16 to use standard address for
| |
| − | | |
| − | {| class="wikitable"
| |
| − | ! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
| |
| − | |-
| |
| − | |style="background-color:#AAF;"| C
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |style="background-color:#BBB;"| 0
| |
| − | |}
| |
| − | | |
| − | == Appendix ==
| |
| − | === Programmable processor and emulation ===
| |
| − | Here is a pseudo code in C to handle NEO mappers extension for programmable processor based cartridges or for emulators:
| |
| − | | |
| − | NEO-16 mapper:
| |
| − | <syntaxhighlight lang="c">
| |
| − | const uint8* romData; // ROM data
| |
| − | uint16 bankValue[3]; // Bank switching register value
| |
| − | | |
| − | // Extended function prototypes
| |
| − | typedef void (*funcEnable_t)(bool, uint8);
| |
| − | typedef void (*funcWrite_t)(uint16, uint8);
| |
| − | typedef uint8 (*funcRead_t)(uint16);
| |
| − | // Extended functions table
| |
| − | funcEnable_t funcEnableTable[32];
| |
| − | funcWrite_t funcWriteTable[3];
| |
| − | funcRead_t funcReadTable[3];
| |
| − | | |
| − | // Handle device initialization
| |
| − | void NEO16_Init()
| |
| − | {
| |
| − | for (uint8 i = 0; i < 3; i++)
| |
| − | {
| |
| − | bankValue[i] = 0x0000;
| |
| − | funcWriteTable[i] = NULL;
| |
| − | funcReadTable[i] = NULL;
| |
| − | }
| |
| − | for (uint8 i = 0; i < 32; i++)
| |
| − | funcEnableTable[i] = NULL;
| |
| − | }
| |
| − | | |
| − | // Handle write access
| |
| − | void NEO16_Write(uint16 address, uint8 value)
| |
| − | {
| |
| − | uint8 bank = ((address >> 12) & 0x03) - 1; // Get the corresponding bank number
| |
| − | if (bank > 2)
| |
| − | return; // skip
| |
| − | | |
| − | if (funcWriteTable[bank] != NULL) // Check for bank write callback
| |
| − | {
| |
| − | funcWriteTable[bank](address, value);
| |
| − | }
| |
| − | else if ((address & 0x0001) && (value & 0x80)) // Handle extended function
| |
| − | {
| |
| − | uint8 funcId = value & 0x3F; // Get function ID
| |
| − | if (funcEnableTable[funcId] != NULL)
| |
| − | funcEnableTable[funcId](value & 0x40, (address >> 1) & 0xFF); // Execute function specific code
| |
| − | }
| |
| − | else // Write to the given bank register
| |
| − | {
| |
| − | if (address & 1) // Set bank register MSB
| |
| − | bankValue[bank] = ((value & 0x0F) << 8) | (bankValue[bank] & 0x00FF);
| |
| − | else // Set bank register LSB
| |
| − | bankValue[bank] = (bankValue[bank] & 0xFF00) | (value);
| |
| − | }
| |
| − | }
| |
| − | | |
| − | // Handle read access
| |
| − | uint8 NEO16_Read(uint16 address)
| |
| − | {
| |
| − | uint8 bank = address >> 14; // Get the corresponding bank number
| |
| − | if (bank > 2)
| |
| − | return 0xFF; // skip
| |
| − | | |
| − | if (funcReadTable[bank] != NULL) // Check for bank read callback
| |
| − | return funcReadTable[bank](address);
| |
| − | else
| |
| − | return romData[(bankValue[bank]) << 14 + (address & 0x3FFF)];
| |
| − | }
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | === Extension example ===
| |
| − | Here is a pseudo code in C to handle a SRAM extension for NEO mapper:
| |
| − | | |
| − | <syntaxhighlight lang="c">
| |
| − | uint8 sramSeg; // Current SRAM segment [0:15]
| |
| − | uint8 sramBank; // Current bank where SRAM is selected (0xFF if not selected)
| |
| − | uint8* sramData; // SRAM data (hardware specific)
| |
| − | | |
| − | // Write to SRAM
| |
| − | void SRAM_Write(uint16 address, uint8 value)
| |
| − | {
| |
| − | sramData[(sramSeg * 0x2000) + (address & 0x1FFF)] = value; //
| |
| − | }
| |
| − | | |
| − | // Read from SRAM
| |
| − | uint8 SRAM_Read(uint16 address)
| |
| − | {
| |
| − | return sramData[(sramSeg * 0x2000) + (address & 0x1FFF)];
| |
| − | }
| |
| − | | |
| − | // Enable/disable SRAM feature
| |
| − | void SRAM_Enable(bool enable, uint8 param)
| |
| − | {
| |
| − | if (sramBank != 0xFF) // Disable previous SRAM registration
| |
| − | {
| |
| − | if (funcWriteTable[sramBank] == SRAM_Write)
| |
| − | funcWriteTable[sramBank] = NULL;
| |
| − | if (funcReadTable[sramBank] == SRAM_Read)
| |
| − | funcReadTable[sramBank] = NULL;
| |
| − | sramBank = 0xFF;
| |
| − | }
| |
| − | | |
| − | if (enable) // Enable a SRAM segment in the given bank
| |
| − | {
| |
| − | uint8 bank = param & 0x07; // Get bank number
| |
| − | if (bank > 2)
| |
| − | return; // skip (for NEO-16)
| |
| − | | |
| − | sramSeg = (param >> 4) & 0x0F; // SRAM segment number
| |
| − | sramBank = bank;
| |
| − | funcWriteTable[sramBank] = SRAM_Write; // Register SRAM callbacks
| |
| − | funcReadTable[sramBank] = SRAM_Read;
| |
| − | }
| |
| − | }
| |
| − | | |
| − | // Initialize SRAM feature
| |
| − | void SRAM_Init()
| |
| − | {
| |
| − | sramBank = 0xFF;
| |
| − | funcEnableTable[0x04] = SRAM_Enable; // Register to function 0x04 (SRAM/FRAM feature)
| |
| − | }
| |
| − | </syntaxhighlight>
| |
| − | | |
| − | Then, you just need to call <tt>SRAM_Init()</tt> from <tt>NEO16_Init()</tt> to register the extended feature.
| |