Difference between revisions of "NEO mapper"
From MSX Game Library
(→NEO-8 mapper) |
(→Bank switching cost) |
||
(76 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
+ | <div style="float:right">[[NEO mapper|EN]] | [[NEO mapper/JA|JA]]</div> | ||
Here's a proposal for a mapper format operating with a 16-bit segment register and allowing ROMs larger than the 2/4 MB limit of classic mappers. | Here's a proposal for a mapper format operating with a 16-bit segment register and allowing ROMs larger than the 2/4 MB limit of classic mappers. | ||
− | == Principles == | + | == Specifications == |
+ | |||
+ | === Principles === | ||
This mapper format is designed to facilitate the creation of MSX games, not only by increasing the size of the ROM available for content, but also by offering programmers new possibilities for organizing their code and data. | This mapper format is designed to facilitate the creation of MSX games, not only by increasing the size of the ROM available for content, but also by offering programmers new possibilities for organizing their code and data. | ||
− | Like conventional mappers, the basic idea is to use data write signals to the cartridge to change | + | Like conventional mappers, the basic idea is to use data write signals to the cartridge to change mapper registers value and thus, the ROM segment visible in each of the mapper's banks (sub-pages). So, predefined addresses can be used to write to the mapper registers (see [[#Format|tables below]]). |
Read accesses, however, work as normal accesses to the memory visible through the banks. | Read accesses, however, work as normal accesses to the memory visible through the banks. | ||
+ | |||
+ | The format is inspired by ASCII8/16 mappers and is even compatible with most ROMs using these formats (the only exception being the rare programs that use odd-numbered addresses to switch banks). The aim of this proximity to these classic mappers is to facilitate the work of manufacturers to create cartridge in this new mapper format. | ||
Compared to conventional mappers, this proposal is based on two new main features: | Compared to conventional mappers, this proposal is based on two new main features: | ||
* A 16-bit segment register, | * A 16-bit segment register, | ||
− | * Banks covering | + | * Banks covering page #0 of MSX memory space. |
− | + | Usage of page #0 makes it easy to have an extra 16 KB accessible at any time (either by temporarily disabling interrupts for the duration of accesses, or by adding its own ISR). | |
− | For the time being, we propose to reserve the 4 most significant bits for future extensions | + | For the time being, we propose to reserve the 4 most significant bits of the 16-bit bank registers for future extensions of the format (such as SRAM or sound chips support for example). |
This leaves 12 bits to select which segment is visible in each bank, for a maximum of 4096 segments. | This leaves 12 bits to select which segment is visible in each bank, for a maximum of 4096 segments. | ||
The reserved bits, must be set to 0. | The reserved bits, must be set to 0. | ||
Line 36: | Line 41: | ||
The maximum ROM size is therefore 32 MB (for 8 KB segments) or 64 MB (for 16 KB segments). | The maximum ROM size is therefore 32 MB (for 8 KB segments) or 64 MB (for 16 KB segments). | ||
− | == | + | === Write Access === |
− | Write access to the mapper is use to change the value of the | + | Write access to the mapper is use to change the value of the bank switching register (where you can select the ROM segment visible through a bank). |
− | + | Bellow is the list of the predefined segment switching addresses. | |
As this new mapper uses 16-bit segment switching registers, it uses 2 bytes for the segment number to be selected in each bank. | As this new mapper uses 16-bit segment switching registers, it uses 2 bytes for the segment number to be selected in each bank. | ||
All even-numbered addresses (bit #0 of the address set to 0) access the low byte of the 16-bit register, while odd-numbered addresses (bit #0 of the address set to 1) access the high byte. | All even-numbered addresses (bit #0 of the address set to 0) access the low byte of the 16-bit register, while odd-numbered addresses (bit #0 of the address set to 1) access the high byte. | ||
− | This way, the segment number can be initialized at once with the Z80 instructions for 16-bit memory write access. | + | This way, the segment number can be initialized at once with the [[#Bank switching cost|Z80 instructions for 16-bit memory write access]]. |
− | === NEO-8 mapper === | + | ==== NEO-8 mapper ==== |
* Size of a segment: 8 KB | * Size of a segment: 8 KB | ||
Line 52: | Line 57: | ||
! Bank (8kB) !! Switching address !! Initial segment | ! Bank (8kB) !! Switching address !! Initial segment | ||
|- | |- | ||
− | | 0: 0000h~1FFFh || 5000h (mirror at 1000h and | + | | 0: 0000h~1FFFh || 5000h (mirror at 1000h, 9000h and D000h) || 0000h |
|- | |- | ||
− | | 1: 2000h~3FFFh || 5800h (mirror at 1800h and | + | | 1: 2000h~3FFFh || 5800h (mirror at 1800h, 9800h and D800h) || 0000h |
|- | |- | ||
− | | 2: 4000h~5FFFh || 6000h (mirror at 2000h and | + | | 2: 4000h~5FFFh || 6000h (mirror at 2000h, A000h and E000h) || 0000h |
|- | |- | ||
− | | 3: 6000h~7FFFh || 6800h (mirror at 2800h and | + | | 3: 6000h~7FFFh || 6800h (mirror at 2800h, A800h and E800h) || 0000h |
|- | |- | ||
− | | 4: 8000h~9FFFh || 7000h (mirror at 3000h and | + | | 4: 8000h~9FFFh || 7000h (mirror at 3000h, B000h and F000h) || 0000h |
|- | |- | ||
− | | 5: A000h~BFFFh || 7800h (mirror at 3800h and | + | | 5: A000h~BFFFh || 7800h (mirror at 3800h, B800h and F800h) || 0000h |
|} | |} | ||
* Maximum number of segments: 4096 | * Maximum number of segments: 4096 | ||
* Maximum ROM size: 32 MB | * Maximum ROM size: 32 MB | ||
− | + | ==== NEO-16 mapper ==== | |
− | |||
− | === NEO-16 mapper === | ||
* Size of a segment: 16 KB | * Size of a segment: 16 KB | ||
Line 76: | Line 79: | ||
! Bank (16kB) !! Switching address !! Initial segment | ! Bank (16kB) !! Switching address !! Initial segment | ||
|- | |- | ||
− | | 0: 0000h~3FFFh || 5000h (mirror at 1000h and | + | | 0: 0000h~3FFFh || 5000h (mirror at 1000h, 9000h and D000h) || 0000h |
|- | |- | ||
− | | 1: 4000h~7FFFh || 6000h (mirror at 2000h and | + | | 1: 4000h~7FFFh || 6000h (mirror at 2000h, A000h and E000h) || 0000h |
|- | |- | ||
− | | 2: 8000h~BFFFh || 7000h (mirror at 3000h and | + | | 2: 8000h~BFFFh || 7000h (mirror at 3000h, B000h and F000h) || 0000h |
|} | |} | ||
* Maximum number of segments: 4096 | * Maximum number of segments: 4096 | ||
* Maximum ROM size: 64 MB | * Maximum ROM size: 64 MB | ||
+ | |||
+ | === Read Access === | ||
+ | When mapper is selected, read accesses to memory pages 0, 1 and 2 (addresses 0000h to BFFFh), are redirected to a given ROM segment according to the value of the bank register corresponding to the address. | ||
+ | |||
+ | For page 3, read accesses are invalid and the value returned is undefined and should not be used. Implementations of the NEO mapper should return the value FFh if page 3 is read, but this value is not guaranteed by the mapper specifications. | ||
=== Detection === | === Detection === | ||
− | For emulators and flash tool to detect the NEO mappers, the ROM have to include the following | + | For emulators and flash tool to detect the NEO mappers, the ROM have to include the following 8 bytes signature right after the 16 bytes ROM header: |
+ | * "<tt>ROM_NEO8</tt>" for NEO-8 mapper, | ||
+ | * "<tt>ROM_NE16</tt>" for NEO-16 mapper. | ||
+ | |||
+ | The ROM header (starting with "AB") must be in the first ROM segment at offset 0. | ||
+ | The signature is therefore located at offset 16 of the ROM and will be visible to the Z80 on start-up at addresses 0010h, 4010h and 8010h. | ||
+ | |||
+ | <u>Note</u>: Signature characters have been carefully choosed to prevent existing ROMs to generate false positive signature (See [[ROM type signature]]). | ||
+ | |||
+ | == Support == | ||
+ | |||
+ | === Hardware === | ||
+ | |||
+ | * '''MSX Pico''': Full support for NEO-8 and NEO-16 mappers up to 15 MB (starting with firmware 1.25). | ||
+ | * '''Mega-USB 512''': ''Incomming hardware...'' | ||
+ | |||
+ | === Emulator === | ||
+ | |||
+ | * {{Emulicious}} '''Emulicious''': Full support for NEO-8 and NEO-16 mappers. | ||
+ | * {{openMSX}} '''openMSX''': Full support for NEO-8 and NEO-16 mappers. Available in the development builds start from Feb 21 2024 ([https://openmsx.vampier.net/zips/ Windows builds]). | ||
+ | |||
+ | === MSXgl === | ||
+ | |||
+ | Both NEO-8 and NEO-16 mappers are supported. Use respectively <tt>ROM_NEO8</tt> and <tt>ROM_NEO16</tt> as target format. | ||
− | It | + | MSXgl uses macros to wrap quick bank switching mechanisms. It would therefore be totally transparent for a user to switch, for example, from an ASCII8 or even Konami-SCC mapper, to an NEO-8 mapper. |
+ | |||
+ | <syntaxhighlight lang="c"> | ||
+ | #define SET_BANK_SEGMENT(bank, segment) /* ... */ | ||
+ | |||
+ | // Make segment #30 visible through bank #1 | ||
+ | SET_BANK_SEGMENT(1, 30); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | MSXgl initialize the banks with a unique segment each, to offer the largest possible space available to the user: | ||
+ | |||
+ | <img style="width:400px; margin:0.5em;" src="https://raw.githubusercontent.com/aoineko-fr/MSXgl/main/engine/doc/mapper_neo8.png" /> | ||
+ | <img style="width:400px; margin:0.5em;" src="https://raw.githubusercontent.com/aoineko-fr/MSXgl/main/engine/doc/mapper_neo16.png" /> | ||
+ | |||
+ | <u>Note</u>: When the application start, segment at 0x4000 always point to segment 0 that include the ROM header. | ||
== Appendix == | == Appendix == | ||
Line 94: | Line 139: | ||
=== Segment switching address format === | === Segment switching address format === | ||
− | + | From a software point of view, the segment switching address is defined as: | |
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 106: | Line 151: | ||
|} | |} | ||
Where: | Where: | ||
− | * 'PP' (0-3) is the page selection for the MSX to redirect access to the mappers slot | + | * 'PP' (0-3) is the page selection for the MSX to redirect access to the mappers slot. Those bits are ignored by the mapper and contribute to mirroring, but the mapper registers can only be accessed from selected pages. |
− | * 'BBB' ( | + | * 'BBB' (0-7) is the bank's register to write in. All unspecified values are discarded. |
+ | :{| class="wikitable" | ||
+ | ! Bank !! NEO-8 !! NEO-16 | ||
+ | |- | ||
+ | | 0 || 010 || 010 | ||
+ | |- | ||
+ | | 1 || 011 || 100 | ||
+ | |- | ||
+ | | 2 || 100 || 110 | ||
+ | |- | ||
+ | | 3 || 101 || | ||
+ | |- | ||
+ | | 4 || 110 || | ||
+ | |- | ||
+ | | 5 || 111 || | ||
+ | |} | ||
* 'R' (0-1) is the segment switching register's byte selector (0: less significant byte; 1: most significant byte). | * 'R' (0-1) is the segment switching register's byte selector (0: less significant byte; 1: most significant byte). | ||
* 'x' can be any value (generating mirroring). | * 'x' can be any value (generating mirroring). | ||
+ | |||
+ | So, mirroring occurs on all addresses from the given switching address +2 to the switching address +7FEh on all even-numbered addresses. For example, 5000h is mirrored at 5002h~57FEh. | ||
=== Bank switching cost === | === Bank switching cost === | ||
The cost of switching only the lower or higher byte of the 16-bit segment register is the same that switching segment for standard ASCII/Konami mappers. | The cost of switching only the lower or higher byte of the 16-bit segment register is the same that switching segment for standard ASCII/Konami mappers. | ||
− | + | <syntaxhighlight lang="ini"> | |
− | + | ; Direct access | |
− | + | LD A,n ; 8 t-states | |
− | + | LD (nn),A ; 14 t-states | |
− | + | ||
− | + | ; Indirect access | |
− | + | LD HL,nn ; 11 t-states | |
+ | LD (HL),n ; 11 t-states | ||
+ | </syntaxhighlight> | ||
Although a program can avoid having to change the 2 bytes of the segment register at once, there are cases where this may be necessary. In such cases, the cost is higher, but remains reasonable. | Although a program can avoid having to change the 2 bytes of the segment register at once, there are cases where this may be necessary. In such cases, the cost is higher, but remains reasonable. | ||
− | + | <syntaxhighlight lang="ini"> | |
− | + | ; Direct access | |
− | + | LD HL,nn ; 11 t-states | |
− | + | LD (nn),HL ; 17 t-states | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ; Indirect access | |
+ | LD DE,nn ; 11 t-states | ||
+ | LD HL,nn ; 11 t-states | ||
+ | LD (HL),E ; 8 t-states | ||
+ | INC HL ; 7 t-states | ||
+ | LD (HL),D ; 8 t-states | ||
+ | </syntaxhighlight> | ||
− | + | == Change log == | |
− | + | * Version 1.0 (2024/02/12) | |
− | + | ** Original version | |
− | + | * Version 1.1 (2024/02/20) | |
+ | ** Changed mappers signature to minimize the risk of an old cartridge generating a false positive and to comply to [[ROM type signature]] format. | ||
+ | ** Added clarification on PP and BBB values for bank switching addresses. | ||
+ | ** Added clarification for read access to the mapper and especially when try to read the page 3. | ||
[[Category:Proposal]][[Category:Proposal/Mapper]] | [[Category:Proposal]][[Category:Proposal/Mapper]] |
Latest revision as of 19:46, 9 November 2024
Here's a proposal for a mapper format operating with a 16-bit segment register and allowing ROMs larger than the 2/4 MB limit of classic mappers.
Contents
Specifications
Principles
This mapper format is designed to facilitate the creation of MSX games, not only by increasing the size of the ROM available for content, but also by offering programmers new possibilities for organizing their code and data.
Like conventional mappers, the basic idea is to use data write signals to the cartridge to change mapper registers value and thus, the ROM segment visible in each of the mapper's banks (sub-pages). So, predefined addresses can be used to write to the mapper registers (see tables below). Read accesses, however, work as normal accesses to the memory visible through the banks.
The format is inspired by ASCII8/16 mappers and is even compatible with most ROMs using these formats (the only exception being the rare programs that use odd-numbered addresses to switch banks). The aim of this proximity to these classic mappers is to facilitate the work of manufacturers to create cartridge in this new mapper format.
Compared to conventional mappers, this proposal is based on two new main features:
- A 16-bit segment register,
- Banks covering page #0 of MSX memory space.
Usage of page #0 makes it easy to have an extra 16 KB accessible at any time (either by temporarily disabling interrupts for the duration of accesses, or by adding its own ISR).
For the time being, we propose to reserve the 4 most significant bits of the 16-bit bank registers for future extensions of the format (such as SRAM or sound chips support for example). This leaves 12 bits to select which segment is visible in each bank, for a maximum of 4096 segments. The reserved bits, must be set to 0.
Higher byte | Lower byte | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0 | 0 | 0 | 0 | Segment MSB | Segment LSB |
The maximum ROM size is therefore 32 MB (for 8 KB segments) or 64 MB (for 16 KB segments).
Write Access
Write access to the mapper is use to change the value of the bank switching register (where you can select the ROM segment visible through a bank). Bellow is the list of the predefined segment switching addresses.
As this new mapper uses 16-bit segment switching registers, it uses 2 bytes for the segment number to be selected in each bank. All even-numbered addresses (bit #0 of the address set to 0) access the low byte of the 16-bit register, while odd-numbered addresses (bit #0 of the address set to 1) access the high byte. This way, the segment number can be initialized at once with the Z80 instructions for 16-bit memory write access.
NEO-8 mapper
- Size of a segment: 8 KB
- Segment switching addresses:
Bank (8kB) | Switching address | Initial segment |
---|---|---|
0: 0000h~1FFFh | 5000h (mirror at 1000h, 9000h and D000h) | 0000h |
1: 2000h~3FFFh | 5800h (mirror at 1800h, 9800h and D800h) | 0000h |
2: 4000h~5FFFh | 6000h (mirror at 2000h, A000h and E000h) | 0000h |
3: 6000h~7FFFh | 6800h (mirror at 2800h, A800h and E800h) | 0000h |
4: 8000h~9FFFh | 7000h (mirror at 3000h, B000h and F000h) | 0000h |
5: A000h~BFFFh | 7800h (mirror at 3800h, B800h and F800h) | 0000h |
- Maximum number of segments: 4096
- Maximum ROM size: 32 MB
NEO-16 mapper
- Size of a segment: 16 KB
- Segment switching addresses:
Bank (16kB) | Switching address | Initial segment |
---|---|---|
0: 0000h~3FFFh | 5000h (mirror at 1000h, 9000h and D000h) | 0000h |
1: 4000h~7FFFh | 6000h (mirror at 2000h, A000h and E000h) | 0000h |
2: 8000h~BFFFh | 7000h (mirror at 3000h, B000h and F000h) | 0000h |
- Maximum number of segments: 4096
- Maximum ROM size: 64 MB
Read Access
When mapper is selected, read accesses to memory pages 0, 1 and 2 (addresses 0000h to BFFFh), are redirected to a given ROM segment according to the value of the bank register corresponding to the address.
For page 3, read accesses are invalid and the value returned is undefined and should not be used. Implementations of the NEO mapper should return the value FFh if page 3 is read, but this value is not guaranteed by the mapper specifications.
Detection
For emulators and flash tool to detect the NEO mappers, the ROM have to include the following 8 bytes signature right after the 16 bytes ROM header:
- "ROM_NEO8" for NEO-8 mapper,
- "ROM_NE16" for NEO-16 mapper.
The ROM header (starting with "AB") must be in the first ROM segment at offset 0. The signature is therefore located at offset 16 of the ROM and will be visible to the Z80 on start-up at addresses 0010h, 4010h and 8010h.
Note: Signature characters have been carefully choosed to prevent existing ROMs to generate false positive signature (See ROM type signature).
Support
Hardware
- MSX Pico: Full support for NEO-8 and NEO-16 mappers up to 15 MB (starting with firmware 1.25).
- Mega-USB 512: Incomming hardware...
Emulator
- Emulicious: Full support for NEO-8 and NEO-16 mappers.
- openMSX: Full support for NEO-8 and NEO-16 mappers. Available in the development builds start from Feb 21 2024 (Windows builds).
MSXgl
Both NEO-8 and NEO-16 mappers are supported. Use respectively ROM_NEO8 and ROM_NEO16 as target format.
MSXgl uses macros to wrap quick bank switching mechanisms. It would therefore be totally transparent for a user to switch, for example, from an ASCII8 or even Konami-SCC mapper, to an NEO-8 mapper.
#define SET_BANK_SEGMENT(bank, segment) /* ... */ // Make segment #30 visible through bank #1 SET_BANK_SEGMENT(1, 30);
MSXgl initialize the banks with a unique segment each, to offer the largest possible space available to the user:
Note: When the application start, segment at 0x4000 always point to segment 0 that include the ROM header.
Appendix
Segment switching address format
From a software point of view, the segment switching address is defined as:
16-bit address | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
P | P | B | B | B | x | x | x | x | x | x | x | x | x | x | R |
Where:
- 'PP' (0-3) is the page selection for the MSX to redirect access to the mappers slot. Those bits are ignored by the mapper and contribute to mirroring, but the mapper registers can only be accessed from selected pages.
- 'BBB' (0-7) is the bank's register to write in. All unspecified values are discarded.
Bank NEO-8 NEO-16 0 010 010 1 011 100 2 100 110 3 101 4 110 5 111
- 'R' (0-1) is the segment switching register's byte selector (0: less significant byte; 1: most significant byte).
- 'x' can be any value (generating mirroring).
So, mirroring occurs on all addresses from the given switching address +2 to the switching address +7FEh on all even-numbered addresses. For example, 5000h is mirrored at 5002h~57FEh.
Bank switching cost
The cost of switching only the lower or higher byte of the 16-bit segment register is the same that switching segment for standard ASCII/Konami mappers.
; Direct access LD A,n ; 8 t-states LD (nn),A ; 14 t-states ; Indirect access LD HL,nn ; 11 t-states LD (HL),n ; 11 t-states
Although a program can avoid having to change the 2 bytes of the segment register at once, there are cases where this may be necessary. In such cases, the cost is higher, but remains reasonable.
; Direct access LD HL,nn ; 11 t-states LD (nn),HL ; 17 t-states ; Indirect access LD DE,nn ; 11 t-states LD HL,nn ; 11 t-states LD (HL),E ; 8 t-states INC HL ; 7 t-states LD (HL),D ; 8 t-states
Change log
- Version 1.0 (2024/02/12)
- Original version
- Version 1.1 (2024/02/20)
- Changed mappers signature to minimize the risk of an old cartridge generating a false positive and to comply to ROM type signature format.
- Added clarification on PP and BBB values for bank switching addresses.
- Added clarification for read access to the mapper and especially when try to read the page 3.