Difference between revisions of "NEO mapper/Extension"

From MSX Game Library

< NEO mapper

(→‎0x05: Activate device)
(→‎Programmable processor and emulation)
 
(26 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. In that case, the mapper bank register is not modified.
+
The extension adds a set of '''functions''' that can be assigned to each bank of the [[NEO mapper]]. The function of a bank defines what this bank gives access to (ROM through the mapper, cartridge information, RAM, SRAM, sound chip, etc.).
  
−
All other write operations should be considered normal access to the mapper's bank register.
+
* At reset, every bank is assigned function 00h (NEO mapper): the base [[NEO mapper]] behavior is unchanged as long as no other function is selected.
 +
* Functions are selected by writing to the '''extension area''' of a bank that is currently in NEO mapper mode (see [[#Write decoding|Write decoding]]).
 +
* The bank that receives the write (given by the address) and the bank that is configured (given by the ''Bank'' field) are independent: a bank can be configured from any other bank that is still in NEO mapper mode.
 +
* Functions 00h (NEO mapper) and 01h (Cartridge information) are mandatory. All others are optional; function 01h tells which ones are supported by the cartridge.
 +
* Function IDs are assigned by this specification only. Unassigned IDs are reserved and must not be used by implementations.
  
−
The data contains:
+
==== Function selection ====
−
* The number of an extended function in the mapper
+
 
−
* A bit indicating whether the function should be enabled or disabled
+
Within a bank in NEO mapper mode, any write with address bits 11-13 set to 0 is a function selection. In that case, the bank switching registers are not modified.
  
−
The address contains an 8-bit parameter to be passed to the function.
 
 
{|
 
{|
 
|-
 
|-
Line 25: Line 28:
 
|-
 
|-
 
|style="background-color:#BBB;" colspan="2"| Page
 
|style="background-color:#BBB;" colspan="2"| Page
−
|style="background-color:#BBB;" colspan="3"| Bank
+
|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:#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:#AAF;" colspan="8"| Parameter
+
|style="background-color:#AAF;" colspan="4"| Function
−
|style="background-color:#FAA;"| 1
 
 
|}
 
|}
 
|
 
|
Line 37: Line 44:
 
! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
 
! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
 
|-
 
|-
−
|style="background-color:#FAA;"| 1
+
|style="background-color:#AAF;" colspan="8"| Parameter
−
|style="background-color:#AAF;"| A
 
−
|style="background-color:#BBB;"| 0
 
−
|style="background-color:#AAF;" colspan="5"| Function
 
 
|}
 
|}
 
|}
 
|}
 +
* '''Page''' (0~3): ignored by the mapper, as for the bank switching registers.
 +
* '''Bank''' (0~7): destination bank to configure. Values above the last bank (5 for NEO-8, 2 for NEO-16) are ignored.
 +
* '''Function''' (0~15): ID of the function to assign to the destination bank.
 +
* '''Parameter''': data byte passed to the function. Its meaning is defined by each function; functions without parameter expect 0.
 +
* Address bits 4~7 are reserved and must be 0. Writes with a non-zero value in these bits are ignored.
 +
* Selecting an unsupported function, or a bank that doesn't exist, is ignored: the destination bank keeps its current function.
 +
 +
The function selection address is therefore:
 +
 +
: '''Address = Page × 4000h + Bank × 100h + Function'''
 +
 +
Function selection is done with an 8-bit write. Exceptions are described in the related function.
 +
 +
==== Write decoding ====
 +
 +
Each write to the cartridge is handled according to the function of the bank that contains the address (<code>address >> 13</code> for NEO-8, <code>address >> 14</code> for NEO-16):
 +
 +
* '''Bank in NEO mapper mode''' (function 00h):
 +
** address bits 11~13 = 0: function selection (see above);
 +
** otherwise: bank switching register access, as defined in the [[NEO mapper]] specification.
 +
* '''Bank in any other mode''': the write is handled by the function, as defined in its description (written to RAM, ignored for read-only functions, etc.). No register access or function selection is decoded through this bank.
 +
 +
Notes:
 +
* A bank switching register can be written while its bank is not in NEO mapper mode. The register is updated but has no visible effect until the bank returns to function 00h.
 +
* Selecting function 00h returns the bank to the ROM segment last selected for it.
 +
 +
==== Read access ====
 +
 +
Read accesses return the content provided by the function of the bank that contains the address. As in the base specification, reads in page 3 are undefined.
 +
 +
==== Limitations ====
 +
 +
Because register access and function selection are only decoded through banks in NEO mapper mode, a program must always keep at least one bank in this mode that contains the extension area:
 +
 +
* NEO-16: any bank (0, 1 or 2). Each bank contains the extension area and a mirror of all bank switching registers.
 +
* NEO-8: an even-numbered bank (0, 2 or 4). Only even-numbered banks contain the extension area and the registers of banks 0 and 1. Odd-numbered banks (1, 3, 5) only contain the registers of banks 2 to 5.
  
 
=== Functions ===
 
=== Functions ===
−
==== 0x00: Cartridge information ====
+
==== 00h: NEO mapper (mandatory) ====
−
When activated, any read access to the given bank will return the cartridge information (8 KB, mirrored on NEO-16).
+
Activate access to the cartridge ROM mapper through the given bank (default mode)
 +
 
 +
<u>Parameter</u>: Not used
 +
 
 +
<u>Read</u>: Read ROM segment content according to bank register value
 +
 
 +
<u>Write</u>: Change bank register value or activate extended function for a given bank
 +
 
 +
<u>Information</u>: NEO Mapper version number
 
{| class="wikitable"
 
{| class="wikitable"
−
|+ PARAMETER
+
! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
 
|-
 
|-
−
! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
+
|colspan="4"| Major ||colspan="4"| Minor
−
|-
 
−
|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:#AAF;" colspan="5"| ROM Bank
 
 
|}
 
|}
  
−
Examples:
+
==== 01h: Cartridge information (mandatory) ====
 +
Activate read access to the cartridge information data through the given bank (256 bytes mirrored)
 +
 
 +
<u>Parameter</u>: Not used
 +
 
 +
<u>Read</u>: Read cartridge information
 
{| class="wikitable"
 
{| class="wikitable"
 +
!rowspan="2"| Offset !!rowspan="2"| Size !!rowspan="2"| Description !!colspan="8"| Content
 
|-
 
|-
−
! Action || Pseudo-code
+
! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
 
|-
 
|-
−
| Activate information in bank 2 of NEO-16 || <tt>[0x7005] = 0xC0</tt>
+
| 0 || 3 || Signature ||colspan="8" style="background-color:#FAA;| "NEO"
 
|-
 
|-
−
| Read information (offset +5) from bank 2 of NEO-16 || <tt>BankSize = [0x8005]</tt>
+
| 3 || 1
 +
| Flag
 +
* S: Bank size (0=8KB, 1=16KB)
 +
|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 || S
 
|-
 
|-
−
| Disactivate information in bank 2 of NEO-16 || <tt>[0x7005] = 0x80</tt>
+
| 4 || 2 || Number of segments ||colspan="8"| 4~16384
 +
|-"
 +
| 6 || 10 || ''Reserved'' ||colspan="8" style="background-color:#BBB;"| 0
 +
|-
 +
| 16 || 1 || Function 0 support (NEO) ||colspan="4" style="background-color:#FAA;| 1 ||colspan="4" style="background-color:#FAA;| 3
 +
|-
 +
| 17 || 1 || Function 1 support (Info) ||colspan="8" style="background-color:#FAA;| 1
 +
|-
 +
| 18 || 1 || Function 2 support ||colspan="8"| >0 if supported
 +
|-
 +
| 19 || 1 || Function 3 support ||colspan="8"| >0 if supported
 +
|-
 +
| 20 || 1 || Function 4 support (RAM) ||colspan="8"| >0 if supported
 +
|-
 +
| 21 || 1 || Function 5 support ||colspan="8"| >0 if supported
 +
|-
 +
| 22 || 1 || Function 6 support (SRAM) ||colspan="8"| >0 if supported
 +
|-
 +
| 23 || 1 || Function 7 support ||colspan="8"| >0 if supported
 +
|-
 +
| 24 || 1 || Function 8 support (SCC) ||colspan="8"| >0 if supported
 +
|-
 +
| 25 || 1 || Function 9 support (SP-OPL4) ||colspan="8"| >0 if supported
 +
|-
 +
| 26 || 1 || Function 10 support ||colspan="8"| >0 if supported
 +
|-
 +
| 27 || 1 || Function 11 support ||colspan="8"| >0 if supported
 +
|-
 +
| 28 || 1 || Function 12 support (Am9511) ||colspan="8"| >0 if supported
 +
|-
 +
| 29 || 1 || Function 13 support (Geo3D)||colspan="8"| >0 if supported
 +
|-
 +
| 30 || 1 || Function 14 support ||colspan="8"| >0 if supported
 +
|-
 +
| 31 || 1 || Function 15 support ||colspan="8"| >0 if supported
 +
|-
 +
| 32 || 224 || ''Reserved'' ||colspan="8" style="background-color:#BBB;"| 0
 
|}
 
|}
  
−
==== 0x01: Cartridge configuration ====
+
<u>Write</u>: No effect
  
−
==== 0x04: Activate SRAM/FRAM ====
+
<u>Information</u>: Cartridge information version number (1)
−
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).
+
==== 02h: ''Reserved'' ====
 +
Reserved for possible future use to control the NEO cartridge from within the program.
  
−
Up to 16 segments can be accessed, for a total capacity of 128 KB.
+
==== 03h: ''Reserved'' ====
 +
 
 +
==== 04h: RAM ====
 +
Activate read/write access to RAM through the given bank. RAM segment is the same size than ROM segment.
 +
 
 +
<u>Parameter</u>:
 
{| class="wikitable"
 
{| class="wikitable"
−
|+ PARAMETER
+
! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
 
|-
 
|-
−
! 8 || 7 || 6 || 5 || 4 || 3 || 2 || 1
+
|style="background-color:#AAF;" colspan="8"| RAM segment
 +
|}
 +
Maximum RAM size:
 +
* NEO-8: 256 x 8 KB = 2 MB
 +
* NEO-16: 256 x 16 KB = 4 MB
 +
 
 +
<u>Read</u>: Read RAM content in the selected segment
 +
 
 +
<u>Write</u>: Write RAM content in the selected segment
 +
 
 +
<u>Information</u>: Number of segment in power of 2 (e.g. 8 = 2^8 = 256 segments). 0 means no support.
 +
 
 +
==== 05h: ''Reserved'' ====
 +
Reserved for possible future use of a 16-bit RAM mapper.
 +
 
 +
==== 06h: SRAM/FRAM ====
 +
Activate read/write access to SRAM/FRAM through the given bank (8 KB mirrored on NEO-16)
 +
 
 +
<u>Parameter</u>:
 +
{| class="wikitable"
 +
! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
 
|-
 
|-
−
|style="background-color:#AAF;" colspan="4"| RAM Segment
 
 
|style="background-color:#BBB;"| 0
 
|style="background-color:#BBB;"| 0
−
|style="background-color:#AAF;" colspan="5"| ROM Bank
+
|style="background-color:#BBB;"| 0
 +
|style="background-color:#BBB;"| 0
 +
|style="background-color:#BBB;"| 0
 +
|style="background-color:#AAF;" colspan="4"| Slot
 
|}
 
|}
 +
Maximum size: 16 x 8 KB = 128 KB
 +
 +
<u>Read</u>: Read SRAM/FRAM content in the selected segment
 +
 +
<u>Write</u>: Write SRAM/FRAM content in the selected segment
 +
 +
<u>Information</u>: Number of slot in power of 2 (e.g. 4 = 2^4 = 16 slots). 0 means no support.
 +
 +
==== 07h: ''Reserved'' ====
  
−
==== 0x05: Activate device ====
+
==== 08h: SCC/SCC+ ====
−
Activate or disactivate the given device.
+
Activate access to SCC audio chip through the given bank.
 +
 
 +
Once enabled, access to the bank works the same way as on an SCC cartridge.
 +
 
 +
The SCC function doesn't replace the whole bank: it overlays a 2 KB SCC window at offset +1800h~1FFFh of the destination bank.
 +
Any bank number is valid, but bank #4 is recommended for NEO-8 and #2 for NEO-16 so the SCC can be accessed through the standard SCC memory window from 9800h~9FFFh.
 +
A bank switching register whose mirror is hidden by the SCC window stays accessible through its other mirrored addresses.
 +
 
 +
The bank with the SCC function still counts as a bank in NEO mapper mode for the [[#Limitations|limitations]] above.
 +
 
 +
Selecting function 00h on the bank removes the SCC window. The SCC keeps its register values and keeps generating sound: the window only controls the access to the registers, not the sound chip activity.
 +
 
 +
 
 +
<u>Parameter</u>: The chip version to activate
 
{| class="wikitable"
 
{| class="wikitable"
−
|+ PARAMETER
+
! 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0
−
|-
 
−
! 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
 
|style="background-color:#BBB;"| 0
 
|style="background-color:#BBB;"| 0
 
|style="background-color:#BBB;"| 0
−
|style="background-color:#AAF;" colspan="5"| Device ID
 
 
|}
 
|}
 +
* C: 0=SCC, 1=SCC+
 +
 +
<u>Read</u>:
 +
<u>Write</u>:
 +
* Inside the SCC window: read and write accesses are redirected to the SCC registers. The 256-byte register set is mirrored over the whole window. The behavior of each register (read/write, read-only, write-only) is the same as on the original Konami SCC.
 +
* Outside the SCC window: the bank keeps the NEO mapper behavior:
 +
** read accesses return the ROM segment selected by the bank switching register;
 +
** write accesses are decoded as bank switching register access or function selection, as for a bank in NEO mapper mode.
 +
 +
<u>Information</u>: Chip support
 +
* 0: None
 +
* 1: SCC
 +
* 2: SCC+
 +
* 3: Both
 +
 +
==== 09h: SP-OPL4 ====
 +
''Work in progress...''
 +
 +
==== 0Ah: ''Reserved'' ====
 +
 +
==== 0Bh: ''Reserved'' ====
 +
 +
==== 0Ch: ''Reserved'' ====
 +
 +
==== 0Dh: ''Reserved'' ====
 +
 +
==== 0Eh: ''Reserved'' ====
 +
 +
==== 0Fh: ''Reserved'' ====
  
−
Devices:
+
=== Detection ===
−
* <tt>00</tt>: MSX-Music (OPLL)
+
−
* <tt>01</tt>: MSX-Audio
+
A NEO mapper without the extension (version ≤ 1.2) ignores function selection writes (address bits 11~13 = 0 is not a valid register address). A program can therefore detect the extension by selecting function 01h on a bank in NEO mapper mode and checking for the "<code>NEO</code>" signature at the beginning of this bank, then selecting function 00h to restore the ROM access.
−
* <tt>02</tt>: SCC
+
−
* <tt>03</tt>: SCC+
+
All the information below is read from the cartridge information block, while function 01h is selected on the bank.
−
* <tt>04</tt>: 2nd PSG (port 10h)
+
−
* <tt>05</tt>: Darky (2 x ePSG)
+
Example code for the NEO-16 mapper, whose segments #1 and #2 are visible to the Z80:
−
* <tt>06</tt>: Darky Jr. (2 x PSG)
+
<syntaxhighlight lang="ini">
−
* <tt>08</tt>: OPM (SFK-01, SFG-01 et SFG-05 ver.1)
+
; Checks for the presence of the NEO mapper and returns the mapper's version number
−
* <tt>09</tt>: OPP (SFG-05 ver.2)
+
; Input:
−
* <tt>12</tt>: OPL4
+
; Output: A=NEO mapper version or 0 if not found
−
* <tt>15</tt>: SAM2695
+
NEO_Detect:
 +
xor a
 +
ld (4201h), a ; Info function for bank #2
 +
ld b, a ; B = 0: not found (default)
 +
ld hl, 8000h ; information block
 +
ld a, (hl)
 +
cp 'N'
 +
jr nz, NEO_Detect_End
 +
inc hl
 +
ld a, (hl)
 +
cp 'E'
 +
jr nz, NEO_Detect_End
 +
inc hl
 +
ld a, (hl)
 +
cp 'O'
 +
jr nz, NEO_Detect_End
 +
ld l, 10h ; HL = 8010h: version
 +
ld b, (hl)
 +
NEO_Detect_End:
 +
xor a
 +
ld (4200h), a ; ROM function for bank #2
 +
ld a, b
 +
ret
 +
</syntaxhighlight>
 +
 
 +
==== Function support ====
 +
 +
The support of each function ''n'' (0~15) is given by the byte at offset 16+''n'' of the information block:
 +
* 0: the function is not supported;
 +
* any other value: the function is supported. The meaning of the value (size, options, etc.) is defined in the description of each function.
 +
 +
Functions 00h and 01h are mandatory, so bytes 16 and 17 are always non-zero.
 +
 
 +
Example for a NEO-16 with program in page 1:
 +
<syntaxhighlight lang="ini">
 +
; Check if the given function is supported
 +
; Input: A=Function ID
 +
; Output: A=Support
 +
NEO_GetFuncSupport:
 +
ld hl, 4201h
 +
ld (hl), 0    ; Select Information function in bank 2
 +
add a, 16
 +
ld b, 80h
 +
ld c, a
 +
ld a, (bc)    ; Read function support at 0x8010+Function
 +
ld hl, 4200h
 +
ld (hl), 0    ; Restore NEO mapper function in bank 2
 +
ret
 +
</syntaxhighlight>
  
 
== Appendix ==
 
== Appendix ==
Line 122: Line 336:
 
NEO-16 mapper:
 
NEO-16 mapper:
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
−
const uint8* romData; // ROM data
+
#define BANK_NUM 3
−
uint16 bankValue[3]; // Bank switching register value
+
#define BANK_SIZE (16 * 1024)
 +
#define ROM_SEG_NUM 1024
 +
#define ROM_SEG_MASK (ROM_SEG_NUM - 1)
 +
#define ROM_SIZE (ROM_SEG_NUM * BANK_SIZE)
 +
#define FUNC_NUM 16
  
 
// Extended function prototypes
 
// Extended function prototypes
−
typedef void (*funcEnable_t)(bool, uint8);
+
typedef void (*funcSelect_t)(uint8, uint8);
 
typedef void (*funcWrite_t)(uint16, uint8);
 
typedef void (*funcWrite_t)(uint16, uint8);
 
typedef uint8 (*funcRead_t)(uint16);
 
typedef uint8 (*funcRead_t)(uint16);
−
// Extended functions table
+
 
−
funcEnable_t funcEnableTable[32];
+
// Extended functions tables
−
funcWrite_t funcWriteTable[3];
+
funcSelect_t funcSelectTable[FUNC_NUM] = {0};
−
funcRead_t funcReadTable[3];
+
funcWrite_t funcWriteTable[BANK_NUM];
 +
funcRead_t funcReadTable[BANK_NUM];
 +
 
 +
// Supported extended function initialization
 +
void initMapper();
 +
void initInfo();
 +
void initRAM();
 +
void initSRAM();
 +
 
 +
//=============================================================================
 +
// NEO-16 Interface
 +
//=============================================================================
  
 
// Handle device initialization
 
// Handle device initialization
 
void NEO16_Init()
 
void NEO16_Init()
 
{
 
{
−
for (uint8 i = 0; i < 3; i++)
+
// Mandatory functions
−
{
+
initMapper();
−
bankValue[i] = 0x0000;
+
initInfo();
−
funcWriteTable[i] = NULL;
+
// Optional functions
−
funcReadTable[i] = NULL;
+
initRAM();
−
}
+
initSRAM();
−
for (uint8 i = 0; i < 32; i++)
 
−
funcEnableTable[i] = NULL;
 
 
}
 
}
  
 
// Handle write access
 
// Handle write access
−
void NEO16_Write(uint16 address, uint8 value)
+
void NEO16_Write(uint16 address, uint8 data)
 +
{
 +
uint8 bank = address >> 14; // Get the corresponding bank number
 +
if (bank < BANK_NUM)
 +
funcWriteTable[bank](address, data);
 +
}
 +
 
 +
// Handle read access
 +
uint8 NEO16_Read(uint16 address)
 +
{
 +
uint8 bank = address >> 14; // Get the corresponding bank number
 +
if (bank < BANK_NUM)
 +
return funcReadTable[bank](address);
 +
 
 +
return 0xFF; // skip
 +
}
 +
 
 +
//=============================================================================
 +
// Function 0x00 - ROM Mapper
 +
//=============================================================================
 +
 
 +
// ROM data
 +
extern const uint8* romData;
 +
 
 +
// Bank switching register value
 +
uint16 romSegment[BANK_NUM];
 +
 
 +
void writeMapper(uint16 address, uint8 data)
 
{
 
{
 
uint8 bank = ((address >> 12) & 0x03) - 1; // Get the corresponding bank number
 
uint8 bank = ((address >> 12) & 0x03) - 1; // Get the corresponding bank number
−
if (bank > 2)
+
if (bank < BANK_NUM) // Default mapper
−
return; // skip
 
−
 
 
−
if (funcWriteTable[bank] != NULL) // Check for bank write callback
 
 
{
 
{
−
funcWriteTable[bank](address, value);
+
if (address & 1) // Set bank register MSB
 +
romSegment[bank] = ((data & 0x3F) << 8) | (romSegment[bank] & 0x00FF);
 +
else // Set bank register LSB
 +
romSegment[bank] = (romSegment[bank] & 0xFF00) | (data);
 
}
 
}
−
else if ((address & 0x0001) && (value & 0x80)) // Handle extended function
+
else // Extended function
 
{
 
{
−
uint8 funcId = value & 0x3F; // Get function ID
+
uint8 funcId = address & 0x0F; // Get function ID
−
if (funcEnableTable[funcId] != NULL)
+
bank = (address >> 8) & 0x07; // Get destination bank
−
funcEnableTable[funcId](value & 0x40, (address >> 1) & 0xFF); // Execute function specific code
+
if ((bank < BANK_NUM) && (funcSelectTable[funcId] != NULL)) // Is function supported?
 +
funcSelectTable[funcId](bank, data); // Initialize function specific code
 
}
 
}
−
else // Write to the given bank register
+
}
 +
 
 +
uint8 readMapper(uint16 address)
 +
{
 +
uint8 bank = address >> 14; // Get the corresponding bank number
 +
return romData[((romSegment[bank]) << 14) + (address & 0x3FFF)];
 +
}
 +
 
 +
void selectMapper(uint8 bank, uint8 data)
 +
{
 +
funcWriteTable[bank] = writeMapper;
 +
funcReadTable[bank] = readMapper;
 +
}
 +
 
 +
void initMapper()
 +
{
 +
for (uint8 i = 0; i < BANK_NUM; i++)
 
{
 
{
−
if (address & 1) // Set bank register MSB
+
romSegment[i] = 0x0000;
−
bankValue[bank] = ((value & 0x0F) << 8) | (bankValue[bank] & 0x00FF);
+
selectMapper(i, 0);
−
else // Set bank register LSB
 
−
bankValue[bank] = (bankValue[bank] & 0xFF00) | (value);
 
 
}
 
}
 +
funcSelectTable[0] = selectMapper;
 
}
 
}
 +
 +
//=============================================================================
 +
// Function 0x01 - Cartridge Information
 +
//=============================================================================
  
−
// Handle read access
+
struct info
−
uint8 NEO16_Read(uint16 address)
+
{
 +
char Sign[3];
 +
uint8 Flag;
 +
uint16 SegmentNum;
 +
uint8 _reserved[10];
 +
uint8 Functions[FUNC_NUM]; // Must be different from 0 for supported functions
 +
};
 +
 
 +
const struct info infoData =
 +
{
 +
{ 'N', 'E', 'O' },
 +
0x01, // NEO-16
 +
ROM_SEG_NUM, // 1024 segments (16 MB)
 +
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 +
{
 +
0x13, // F0:  NEO mapper (version 1.3)
 +
1,    // F1:  Info
 +
0,    // F2:
 +
0,    // F3:
 +
5,    // F4:  RAM
 +
0,    // F5:
 +
4,    // F6:  SRAM/FRAM
 +
0,    // F7:
 +
0,    // F8:  SCC
 +
0,    // F9:  SP-OPL4
 +
0,    // F10:
 +
0,    // F11:
 +
0,    // F12: Am9511
 +
0,    // F13: Geo3D
 +
0,    // F14:
 +
0,    // F15:
 +
},
 +
};
 +
 
 +
void writeInfo(uint16 address, uint8 data) {}
 +
 
 +
uint8 readInfo(uint16 address)
 +
{
 +
uint8 index = address & 0xFF; // mirrored every 256 bytes
 +
if (index >= sizeof(struct info))
 +
return 0;
 +
return ((const uint8*)&infoData)[index];
 +
}
 +
 
 +
void selectInfo(uint8 bank, uint8 data)
 
{
 
{
−
uint8 bank = address >> 14; // Get the corresponding bank number
+
funcWriteTable[bank] = writeInfo;
−
if (bank > 2)
+
funcReadTable[bank] = readInfo;
−
return 0xFF; // skip
+
}
  
−
if (funcReadTable[bank] != NULL) // Check for bank read callback
+
void initInfo()
−
return funcReadTable[bank](address);
+
{
−
else
+
funcSelectTable[1] = selectInfo;
−
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:
+
// Function 0x04 - RAM
 +
//=============================================================================
 +
 
 +
#define RAM_SEG_NUM 32
 +
#define RAM_SEG_POW2 5
 +
#define RAM_SEG_MASK (RAM_SEG_NUM - 1)
 +
 
 +
// RAM data
 +
uint8 ramData[16 * 1024 * RAM_SEG_NUM]; // 32 * 16 KB = 512 KB
 +
 
 +
// Bank switching register value
 +
uint8 ramSegment[BANK_NUM];
 +
 
 +
void writeRAM(uint16 address, uint8 data)
 +
{
 +
uint8 bank = address >> 14; // Get the corresponding bank number
 +
ramData[((ramSegment[bank]) << 14) + (address & 0x3FFF)] = data;
 +
}
  
−
<syntaxhighlight lang="c">
+
uint8 readRAM(uint16 address)
−
uint8 sramSeg; // Current SRAM segment [0:15]
+
{
−
uint8 sramBank; // Current bank where SRAM is selected (0xFF if not selected)
+
uint8 bank = address >> 14; // Get the corresponding bank number
−
uint8* sramData; // SRAM data (hardware specific)
+
return ramData[((ramSegment[bank]) << 14) + (address & 0x3FFF)];
 +
}
  
−
// Write to SRAM
+
void selectRAM(uint8 bank, uint8 data)
−
void SRAM_Write(uint16 address, uint8 value)
 
 
{
 
{
−
sramData[(sramSeg * 0x2000) + (address & 0x1FFF)] = value; //
+
ramSegment[bank] = data & RAM_SEG_MASK;
 +
funcWriteTable[bank] = writeRAM;
 +
funcReadTable[bank] = readRAM;
 
}
 
}
  
−
// Read from SRAM
+
void initRAM()
−
uint8 SRAM_Read(uint16 address)
 
 
{
 
{
−
return sramData[(sramSeg * 0x2000) + (address & 0x1FFF)];
+
for (uint8 i = 0; i < BANK_NUM; i++)
 +
ramSegment[i] = 0;
 +
funcSelectTable[4] = selectRAM;
 
}
 
}
  
−
// Enable/disable SRAM feature
+
//=============================================================================
−
void SRAM_Enable(bool enable, uint8 param)
+
// Function 0x06 - SRAM
 +
//=============================================================================
 +
 
 +
#define SRAM_SEG_NUM 16
 +
#define SRAM_SEG_POW2 4
 +
#define SRAM_SEG_MASK (SRAM_SEG_NUM - 1)
 +
 
 +
// SRAM data
 +
uint8 sramData[8 * 1024 * SRAM_SEG_NUM]; // 16 * 8 KB = 128 KB
 +
 
 +
// Bank switching register value
 +
uint8 sramSegment[BANK_NUM];
 +
 
 +
void writeSRAM(uint16 address, uint8 data)
 
{
 
{
−
if (sramBank != 0xFF) // Disable previous SRAM registration
+
uint8 bank = address >> 14; // Get the corresponding bank number
−
{
+
sramData[((sramSegment[bank]) << 13) + (address & 0x1FFF)] = data;
−
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 readSRAM(uint16 address)
−
{
+
{
−
uint8 bank = param & 0x07; // Get bank number
+
uint8 bank = address >> 14; // Get the corresponding bank number
−
if (bank > 2)
+
return sramData[((sramSegment[bank]) << 13) + (address & 0x1FFF)];
−
return; // skip (for NEO-16)
+
}
  
−
sramSeg = (param >> 4) & 0x0F; // SRAM segment number
+
void selectSRAM(uint8 bank, uint8 data)
−
sramBank = bank;
+
{
−
funcWriteTable[sramBank] = SRAM_Write; // Register SRAM callbacks
+
sramSegment[bank] = data & SRAM_SEG_MASK;
−
funcReadTable[sramBank] = SRAM_Read;
+
funcWriteTable[bank] = writeSRAM;
−
}
+
funcReadTable[bank] = readSRAM;
 
}
 
}
  
−
// Initialize SRAM feature
+
void initSRAM()
−
void SRAM_Init()
 
 
{
 
{
−
sramBank = 0xFF;
+
for (uint8 i = 0; i < BANK_NUM; i++)
−
funcEnableTable[0x04] = SRAM_Enable; // Register to function 0x04 (SRAM/FRAM feature)
+
sramSegment[i] = 0;
 +
funcSelectTable[6] = selectSRAM;
 
}
 
}
 
</syntaxhighlight>
 
</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 22:09, 1 November 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

The extension adds a set of functions that can be assigned to each bank of the NEO mapper. The function of a bank defines what this bank gives access to (ROM through the mapper, cartridge information, RAM, SRAM, sound chip, etc.).

  • At reset, every bank is assigned function 00h (NEO mapper): the base NEO mapper behavior is unchanged as long as no other function is selected.
  • Functions are selected by writing to the extension area of a bank that is currently in NEO mapper mode (see Write decoding).
  • The bank that receives the write (given by the address) and the bank that is configured (given by the Bank field) are independent: a bank can be configured from any other bank that is still in NEO mapper mode.
  • Functions 00h (NEO mapper) and 01h (Cartridge information) are mandatory. All others are optional; function 01h tells which ones are supported by the cartridge.
  • Function IDs are assigned by this specification only. Unassigned IDs are reserved and must not be used by implementations.

Function selection

Within a bank in NEO mapper mode, any write with address bits 11-13 set to 0 is a function selection. In that case, the bank switching registers are not modified.

ADDRESS
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Page 0 0 0 Bank 0 0 0 0 Function
DATA
7 6 5 4 3 2 1 0
Parameter
  • Page (0~3): ignored by the mapper, as for the bank switching registers.
  • Bank (0~7): destination bank to configure. Values above the last bank (5 for NEO-8, 2 for NEO-16) are ignored.
  • Function (0~15): ID of the function to assign to the destination bank.
  • Parameter: data byte passed to the function. Its meaning is defined by each function; functions without parameter expect 0.
  • Address bits 4~7 are reserved and must be 0. Writes with a non-zero value in these bits are ignored.
  • Selecting an unsupported function, or a bank that doesn't exist, is ignored: the destination bank keeps its current function.

The function selection address is therefore:

Address = Page × 4000h + Bank × 100h + Function

Function selection is done with an 8-bit write. Exceptions are described in the related function.

Write decoding

Each write to the cartridge is handled according to the function of the bank that contains the address (address >> 13 for NEO-8, address >> 14 for NEO-16):

  • Bank in NEO mapper mode (function 00h):
    • address bits 11~13 = 0: function selection (see above);
    • otherwise: bank switching register access, as defined in the NEO mapper specification.
  • Bank in any other mode: the write is handled by the function, as defined in its description (written to RAM, ignored for read-only functions, etc.). No register access or function selection is decoded through this bank.

Notes:

  • A bank switching register can be written while its bank is not in NEO mapper mode. The register is updated but has no visible effect until the bank returns to function 00h.
  • Selecting function 00h returns the bank to the ROM segment last selected for it.

Read access

Read accesses return the content provided by the function of the bank that contains the address. As in the base specification, reads in page 3 are undefined.

Limitations

Because register access and function selection are only decoded through banks in NEO mapper mode, a program must always keep at least one bank in this mode that contains the extension area:

  • NEO-16: any bank (0, 1 or 2). Each bank contains the extension area and a mirror of all bank switching registers.
  • NEO-8: an even-numbered bank (0, 2 or 4). Only even-numbered banks contain the extension area and the registers of banks 0 and 1. Odd-numbered banks (1, 3, 5) only contain the registers of banks 2 to 5.

Functions

00h: NEO mapper (mandatory)

Activate access to the cartridge ROM mapper through the given bank (default mode)

Parameter: Not used

Read: Read ROM segment content according to bank register value

Write: Change bank register value or activate extended function for a given bank

Information: NEO Mapper version number

7 6 5 4 3 2 1 0
Major Minor

01h: Cartridge information (mandatory)

Activate read access to the cartridge information data through the given bank (256 bytes mirrored)

Parameter: Not used

Read: Read cartridge information

Offset Size Description Content
7 6 5 4 3 2 1 0
0 3 Signature "NEO"
3 1 Flag
  • S: Bank size (0=8KB, 1=16KB)
0 0 0 0 0 0 0 S
4 2 Number of segments 4~16384
6 10 Reserved 0
16 1 Function 0 support (NEO) 1 3
17 1 Function 1 support (Info) 1
18 1 Function 2 support >0 if supported
19 1 Function 3 support >0 if supported
20 1 Function 4 support (RAM) >0 if supported
21 1 Function 5 support >0 if supported
22 1 Function 6 support (SRAM) >0 if supported
23 1 Function 7 support >0 if supported
24 1 Function 8 support (SCC) >0 if supported
25 1 Function 9 support (SP-OPL4) >0 if supported
26 1 Function 10 support >0 if supported
27 1 Function 11 support >0 if supported
28 1 Function 12 support (Am9511) >0 if supported
29 1 Function 13 support (Geo3D) >0 if supported
30 1 Function 14 support >0 if supported
31 1 Function 15 support >0 if supported
32 224 Reserved 0

Write: No effect

Information: Cartridge information version number (1)

02h: Reserved

Reserved for possible future use to control the NEO cartridge from within the program.

03h: Reserved

04h: RAM

Activate read/write access to RAM through the given bank. RAM segment is the same size than ROM segment.

Parameter:

7 6 5 4 3 2 1 0
RAM segment

Maximum RAM size:

  • NEO-8: 256 x 8 KB = 2 MB
  • NEO-16: 256 x 16 KB = 4 MB

Read: Read RAM content in the selected segment

Write: Write RAM content in the selected segment

Information: Number of segment in power of 2 (e.g. 8 = 2^8 = 256 segments). 0 means no support.

05h: Reserved

Reserved for possible future use of a 16-bit RAM mapper.

06h: SRAM/FRAM

Activate read/write access to SRAM/FRAM through the given bank (8 KB mirrored on NEO-16)

Parameter:

7 6 5 4 3 2 1 0
0 0 0 0 Slot

Maximum size: 16 x 8 KB = 128 KB

Read: Read SRAM/FRAM content in the selected segment

Write: Write SRAM/FRAM content in the selected segment

Information: Number of slot in power of 2 (e.g. 4 = 2^4 = 16 slots). 0 means no support.

07h: Reserved

08h: SCC/SCC+

Activate access to SCC audio chip through the given bank.

Once enabled, access to the bank works the same way as on an SCC cartridge.

The SCC function doesn't replace the whole bank: it overlays a 2 KB SCC window at offset +1800h~1FFFh of the destination bank. Any bank number is valid, but bank #4 is recommended for NEO-8 and #2 for NEO-16 so the SCC can be accessed through the standard SCC memory window from 9800h~9FFFh. A bank switching register whose mirror is hidden by the SCC window stays accessible through its other mirrored addresses.

The bank with the SCC function still counts as a bank in NEO mapper mode for the limitations above.

Selecting function 00h on the bank removes the SCC window. The SCC keeps its register values and keeps generating sound: the window only controls the access to the registers, not the sound chip activity.


Parameter: The chip version to activate

7 6 5 4 3 2 1 0
C 0 0 0 0 0 0 0
  • C: 0=SCC, 1=SCC+

Read: Write:

  • Inside the SCC window: read and write accesses are redirected to the SCC registers. The 256-byte register set is mirrored over the whole window. The behavior of each register (read/write, read-only, write-only) is the same as on the original Konami SCC.
  • Outside the SCC window: the bank keeps the NEO mapper behavior:
    • read accesses return the ROM segment selected by the bank switching register;
    • write accesses are decoded as bank switching register access or function selection, as for a bank in NEO mapper mode.

Information: Chip support

  • 0: None
  • 1: SCC
  • 2: SCC+
  • 3: Both

09h: SP-OPL4

Work in progress...

0Ah: Reserved

0Bh: Reserved

0Ch: Reserved

0Dh: Reserved

0Eh: Reserved

0Fh: Reserved

Detection

A NEO mapper without the extension (version ≤ 1.2) ignores function selection writes (address bits 11~13 = 0 is not a valid register address). A program can therefore detect the extension by selecting function 01h on a bank in NEO mapper mode and checking for the "NEO" signature at the beginning of this bank, then selecting function 00h to restore the ROM access.

All the information below is read from the cartridge information block, while function 01h is selected on the bank.

Example code for the NEO-16 mapper, whose segments #1 and #2 are visible to the Z80:

; Checks for the presence of the NEO mapper and returns the mapper's version number
; Input:
; Output: A=NEO mapper version or 0 if not found
NEO_Detect:
	xor		a
	ld		(4201h), a	; Info function for bank #2
	ld		b, a		; B = 0: not found (default)
	ld		hl, 8000h	; information block
	ld		a, (hl)
	cp		'N'
	jr		nz, NEO_Detect_End
	inc		hl
	ld		a, (hl)
	cp		'E'
	jr		nz, NEO_Detect_End
	inc		hl
	ld		a, (hl)
	cp		'O'
	jr		nz, NEO_Detect_End
	ld		l, 10h		; HL = 8010h: version
	ld		b, (hl)
NEO_Detect_End:
	xor		a
	ld		(4200h), a	; ROM function for bank #2
	ld		a, b
	ret

Function support

The support of each function n (0~15) is given by the byte at offset 16+n of the information block:

  • 0: the function is not supported;
  • any other value: the function is supported. The meaning of the value (size, options, etc.) is defined in the description of each function.

Functions 00h and 01h are mandatory, so bytes 16 and 17 are always non-zero.

Example for a NEO-16 with program in page 1:

; Check if the given function is supported
; Input: A=Function ID
; Output: A=Support
NEO_GetFuncSupport:
	ld	hl, 4201h
	ld	(hl), 0     ; Select Information function in bank 2
	add	a, 16
	ld	b, 80h
	ld	c, a
	ld	a, (bc)     ; Read function support at 0x8010+Function
	ld	hl, 4200h
	ld	(hl), 0     ; Restore NEO mapper function in bank 2
	ret

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:

#define BANK_NUM				3
#define BANK_SIZE				(16 * 1024)
#define ROM_SEG_NUM				1024
#define ROM_SEG_MASK			(ROM_SEG_NUM - 1)
#define ROM_SIZE				(ROM_SEG_NUM * BANK_SIZE)
#define FUNC_NUM				16

// Extended function prototypes
typedef void (*funcSelect_t)(uint8, uint8);
typedef void (*funcWrite_t)(uint16, uint8);
typedef uint8 (*funcRead_t)(uint16);

// Extended functions tables
funcSelect_t funcSelectTable[FUNC_NUM] = {0};
funcWrite_t funcWriteTable[BANK_NUM];
funcRead_t funcReadTable[BANK_NUM];

// Supported extended function initialization
void initMapper();
void initInfo();
void initRAM();
void initSRAM();

//=============================================================================
// NEO-16 Interface
//=============================================================================

// Handle device initialization
void NEO16_Init()
{
	// Mandatory functions
	initMapper();
	initInfo();
	// Optional functions
	initRAM();
	initSRAM();
}

// Handle write access
void NEO16_Write(uint16 address, uint8 data)
{
	uint8 bank = address >> 14; // Get the corresponding bank number
	if (bank < BANK_NUM)
		funcWriteTable[bank](address, data);
}

// Handle read access
uint8 NEO16_Read(uint16 address)
{
	uint8 bank = address >> 14; // Get the corresponding bank number
	if (bank < BANK_NUM)
		return funcReadTable[bank](address);

	return 0xFF; // skip
}

//=============================================================================
// Function 0x00 - ROM Mapper
//=============================================================================

// ROM data
extern const uint8* romData; 

// Bank switching register value
uint16 romSegment[BANK_NUM];

void writeMapper(uint16 address, uint8 data)
{
	uint8 bank = ((address >> 12) & 0x03) - 1; // Get the corresponding bank number
	if (bank < BANK_NUM) // Default mapper
	{
		if (address & 1) // Set bank register MSB
			romSegment[bank] = ((data & 0x3F) << 8) | (romSegment[bank] & 0x00FF);
		else // Set bank register LSB
			romSegment[bank] = (romSegment[bank] & 0xFF00) | (data);
	}
	else // Extended function
	{
		uint8 funcId = address & 0x0F; // Get function ID
		bank = (address >> 8) & 0x07; // Get destination bank
		if ((bank < BANK_NUM) && (funcSelectTable[funcId] != NULL)) // Is function supported?
			funcSelectTable[funcId](bank, data); // Initialize function specific code
	}
}

uint8 readMapper(uint16 address)
{
	uint8 bank = address >> 14; // Get the corresponding bank number
	return romData[((romSegment[bank]) << 14) + (address & 0x3FFF)];
}

void selectMapper(uint8 bank, uint8 data)
{
	funcWriteTable[bank] = writeMapper;
	funcReadTable[bank] = readMapper;		
}

void initMapper()
{
	for (uint8 i = 0; i < BANK_NUM; i++)
	{
		romSegment[i] = 0x0000;
		selectMapper(i, 0);		
	}
	funcSelectTable[0] = selectMapper;
}
	
//=============================================================================
// Function 0x01 - Cartridge Information
//=============================================================================

struct info
{
	char	Sign[3];
	uint8	Flag;
	uint16	SegmentNum;
	uint8	_reserved[10];
	uint8	Functions[FUNC_NUM]; // Must be different from 0 for supported functions 
};

const struct info infoData = 
{
	{ 'N', 'E', 'O' },
	0x01, // NEO-16
	ROM_SEG_NUM, // 1024 segments (16 MB)
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{
		0x13, // F0:  NEO mapper (version 1.3)
		1,    // F1:  Info
		0,    // F2:
		0,    // F3:
		5,    // F4:  RAM
		0,    // F5:
		4,    // F6:  SRAM/FRAM
		0,    // F7:
		0,    // F8:  SCC
		0,    // F9:  SP-OPL4
		0,    // F10:
		0,    // F11:
		0,    // F12: Am9511
		0,    // F13: Geo3D
		0,    // F14:
		0,    // F15:
	},
};

void writeInfo(uint16 address, uint8 data) {}

uint8 readInfo(uint16 address)
{
	uint8 index = address & 0xFF; // mirrored every 256 bytes
	if (index >= sizeof(struct info))
		return 0;
	return ((const uint8*)&infoData)[index]; 
}

void selectInfo(uint8 bank, uint8 data)
{
	funcWriteTable[bank] = writeInfo;
	funcReadTable[bank] = readInfo;		
}

void initInfo()
{
	funcSelectTable[1] = selectInfo;
}

//=============================================================================
// Function 0x04 - RAM
//=============================================================================

#define RAM_SEG_NUM				32
#define RAM_SEG_POW2			5
#define RAM_SEG_MASK			(RAM_SEG_NUM - 1)

// RAM data
uint8 ramData[16 * 1024 * RAM_SEG_NUM]; // 32 * 16 KB = 512 KB

// Bank switching register value
uint8 ramSegment[BANK_NUM];

void writeRAM(uint16 address, uint8 data)
{
	uint8 bank = address >> 14; // Get the corresponding bank number
	ramData[((ramSegment[bank]) << 14) + (address & 0x3FFF)] = data;
}

uint8 readRAM(uint16 address)
{
	uint8 bank = address >> 14; // Get the corresponding bank number
	return ramData[((ramSegment[bank]) << 14) + (address & 0x3FFF)];
}

void selectRAM(uint8 bank, uint8 data)
{
	ramSegment[bank] = data & RAM_SEG_MASK;
	funcWriteTable[bank] = writeRAM;
	funcReadTable[bank] = readRAM;		
}

void initRAM()
{
	for (uint8 i = 0; i < BANK_NUM; i++)
		ramSegment[i] = 0;
	funcSelectTable[4] = selectRAM;
}

//=============================================================================
// Function 0x06 - SRAM
//=============================================================================

#define SRAM_SEG_NUM			16
#define SRAM_SEG_POW2			4
#define SRAM_SEG_MASK			(SRAM_SEG_NUM - 1)

// SRAM data
uint8 sramData[8 * 1024 * SRAM_SEG_NUM]; // 16 * 8 KB = 128 KB

// Bank switching register value
uint8 sramSegment[BANK_NUM];

void writeSRAM(uint16 address, uint8 data)
{
	uint8 bank = address >> 14; // Get the corresponding bank number
	sramData[((sramSegment[bank]) << 13) + (address & 0x1FFF)] = data;
}

uint8 readSRAM(uint16 address)
{
	uint8 bank = address >> 14; // Get the corresponding bank number
	return sramData[((sramSegment[bank]) << 13) + (address & 0x1FFF)];
}

void selectSRAM(uint8 bank, uint8 data)
{
	sramSegment[bank] = data & SRAM_SEG_MASK;
	funcWriteTable[bank] = writeSRAM;
	funcReadTable[bank] = readSRAM;		
}

void initSRAM()
{
	for (uint8 i = 0; i < BANK_NUM; i++)
		sramSegment[i] = 0;
	funcSelectTable[6] = selectSRAM;
}