Difference between revisions of "NEO mapper/Extension"

From MSX Game Library

< NEO mapper

(0x05: Activate device)
 
(25 intermediate revisions by the same user not shown)
Line 7: Line 7:
 
=== Principles ===
 
=== Principles ===
  
Any write operation to the NEO mapper with data bit 7 set to 1 and address bit 0 set to 1 is considered an access to extended features.
+
Any write operation to the NEO mapper with data bit 7 set to 1 and address bit 0 set to 1 is considered an 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.
 
All other write operations should be considered normal access to the mapper's bank register.
  
Line 56: Line 57:
 
|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="5"| Bank
+
|style="background-color:#AAF;" colspan="5"| ROM Bank
 +
|}
 +
 
 +
Examples:
 +
{| class="wikitable"
 +
|-
 +
! Action || Pseudo-code
 +
|-
 +
| Activate information in bank 2 of NEO-16 || <tt>[0x7005] = 0xC0</tt>
 +
|-
 +
| Read information (offset +5) from bank 2 of NEO-16 || <tt>BankSize = [0x8005]</tt>
 +
|-
 +
| Disactivate information in bank 2 of NEO-16 || <tt>[0x7005] = 0x80</tt>
 
|}
 
|}
  
Line 62: Line 75:
  
 
==== 0x04: Activate SRAM/FRAM ====
 
==== 0x04: Activate SRAM/FRAM ====
When activated, any read/write access to the specified bank (set as a parameter) is redirected to the given segment of the SRAM/FRAM.
+
When activated, any read/write access to the specified bank (defined in the parameter) is redirected to the selected segment of the SRAM/FRAM.
SRAM/FRAM are accessed via 8 KB segments (on the NEO-16, the segment is mirrored).
 
Up to 16 segments can be accessed, for a total of 128 KB.
 
  
 +
SRAM/FRAM is accessed through 8 KB segments (on the NEO-16, the segment is mirrored).
 +
 +
Up to 16 segments can be accessed, for a total capacity of 128 KB.
 
{| class="wikitable"
 
{| class="wikitable"
 
|+ PARAMETER
 
|+ PARAMETER
Line 71: Line 85:
 
! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
 
! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
 
|-
 
|-
|style="background-color:#AAF;" colspan="4"| Segment
+
|style="background-color:#AAF;" colspan="4"| RAM Segment
 
|style="background-color:#BBB;"| 0
 
|style="background-color:#BBB;"| 0
|style="background-color:#AAF;" colspan="5"| Bank
+
|style="background-color:#AAF;" colspan="5"| ROM Bank
 
|}
 
|}
 +
 +
==== 0x05: Activate device ====
 +
Activate or disactivate the given device.
 +
{| class="wikitable"
 +
|+ PARAMETER
 +
|-
 +
! 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:#AAF;" colspan="5"| Device ID
 +
|}
 +
 +
Devices:
 +
* <tt>00</tt>: MSX-Music (OPLL)
 +
* <tt>01</tt>: MSX-Audio
 +
* <tt>02</tt>: SCC
 +
* <tt>03</tt>: SCC+
 +
* <tt>04</tt>: 2nd PSG (port 10h)
 +
* <tt>05</tt>: Darky (2 x ePSG)
 +
* <tt>06</tt>: Darky Jr. (2 x PSG)
 +
* <tt>08</tt>: OPM (SFK-01, SFG-01 et SFG-05 ver.1)
 +
* <tt>09</tt>: OPP (SFG-05 ver.2)
 +
* <tt>12</tt>: OPL4
 +
* <tt>15</tt>: SAM2695
 +
 +
== 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.

Latest revision as of 23:34, 13 April 2026

⚠️ This page is still in the proposal stage and should not yet be considered an official specification.

Proposal for an extension to the NEO mapper format.

Specifications

Principles

Any write operation to the NEO mapper with data bit 7 set to 1 and address bit 0 set to 1 is considered an 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 data contains:

  • The number of an extended function in the mapper
  • A bit indicating whether the function should be enabled or disabled

The address contains an 8-bit parameter to be passed to the function.

ADDRESS
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Page Bank 0 0 Parameter 1
DATA
7 6 5 4 3 2 1 0
1 A 0 Function

Functions

0x00: Cartridge information

When activated, any read access to the given bank will return the cartridge information (8 KB, mirrored on NEO-16).

PARAMETER
8 7 6 5 4 3 2 1
0 0 0 0 0 ROM Bank

Examples:

Action Pseudo-code
Activate information in bank 2 of NEO-16 [0x7005] = 0xC0
Read information (offset +5) from bank 2 of NEO-16 BankSize = [0x8005]
Disactivate information in bank 2 of NEO-16 [0x7005] = 0x80

0x01: Cartridge configuration

0x04: Activate SRAM/FRAM

When activated, any read/write access to the specified bank (defined in the parameter) is redirected to the selected segment of the SRAM/FRAM.

SRAM/FRAM is accessed through 8 KB segments (on the NEO-16, the segment is mirrored).

Up to 16 segments can be accessed, for a total capacity of 128 KB.

PARAMETER
8 7 6 5 4 3 2 1
RAM Segment 0 ROM Bank

0x05: Activate device

Activate or disactivate the given device.

PARAMETER
8 7 6 5 4 3 2 1
0 0 0 Device ID

Devices:

  • 00: MSX-Music (OPLL)
  • 01: MSX-Audio
  • 02: SCC
  • 03: SCC+
  • 04: 2nd PSG (port 10h)
  • 05: Darky (2 x ePSG)
  • 06: Darky Jr. (2 x PSG)
  • 08: OPM (SFK-01, SFG-01 et SFG-05 ver.1)
  • 09: OPP (SFG-05 ver.2)
  • 12: OPL4
  • 15: SAM2695

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:

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)];
}

Extension example

Here is a pseudo code in C to handle a SRAM extension for NEO mapper:

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)
}

Then, you just need to call SRAM_Init() from NEO16_Init() to register the extended feature.