mirror of
https://github.com/libretro/smsplus-gx.git
synced 2024-12-04 23:56:29 +00:00
455 lines
17 KiB
Plaintext
455 lines
17 KiB
Plaintext
|
|
When you release a port, please include YOUR contact information for users
|
|
to report bugs and other problems.
|
|
|
|
I get a ton of e-mails about a color problem in the Nokia P900 port of SMS
|
|
Plus because the author apparently included my e-mail address (please link
|
|
to my webpage instead) and listed NO contact information for him/herself.
|
|
|
|
Also, let me know when you release a port, so I can forward these types
|
|
of e-mails appropriately.
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
What's changed for SMS Plus v1.2
|
|
|
|
I haven't finished up the porting notes so some things aren't covered yet;
|
|
look at the DOS source for an example.
|
|
|
|
After calling system_init(), use the following functions:
|
|
|
|
system_poweron() - Call once, can run game afterwards
|
|
system_reset() - Can call during gameplay if user wants a hard reset
|
|
system_poweroff() - Call once when done with a game.
|
|
|
|
When loading multiple ROMs in a single session, you'd call poweroff() when
|
|
done with a game, then poweron() after the next one was loaded.
|
|
|
|
SRAM is loaded when poweron() or reset() is called.
|
|
SRAM is saved when poweroff() is called.
|
|
|
|
The SRAM management function has changed:
|
|
|
|
void system_manage_sram(uint8 *sram, int slot, int mode);
|
|
|
|
'mode' is either SRAM_SAVE or SRAM_LOAD.
|
|
The slot parameter is ignored for now.
|
|
If there was SRAM to load, set sms.save = 1;
|
|
Otherwise, clear SRAM to zero.
|
|
See the DOS code for an implementation of this function.
|
|
|
|
Sound emulation
|
|
|
|
The following structure holds sound related information:
|
|
|
|
struct {
|
|
|
|
/* Input parameters */
|
|
int sample_rate;
|
|
int fps;
|
|
uint32 psg_clock;
|
|
uint32 fm_clock;
|
|
int fm_which;
|
|
void (*mixer_callback)(int16 **stream, int16 **output, int length);
|
|
|
|
/* Working data */
|
|
int16 *stream[STREAM_MAX];
|
|
int16 *output[2];
|
|
|
|
/* Outputs */
|
|
int enabled;
|
|
int buffer_size;
|
|
int sample_count;
|
|
} snd;
|
|
|
|
Normally you would set up this structure before calling system_init().
|
|
You can change the input parameters and call sound_init() again to change
|
|
them. Here are how the parameters should be used:
|
|
|
|
snd.sample_rate Set to the desired sample rate, e.g. 22050, 44100.
|
|
Set to 0 to disable sound emulation.
|
|
|
|
snd.fps Set to 50 (PAL) or 60 (NTSC) to specify the emulated
|
|
sound replay rate. PAL consoles are not completely
|
|
supported yet, I would advise leaving this at 60.
|
|
|
|
snd.psg_clock Set to the SN76489 clock speed.
|
|
Normally this is 3579545. (3.58 MHz)
|
|
|
|
snd.fm_clock Set to the YM2413 clock speed.
|
|
Normally this is 3579545. (3.58 MHz)
|
|
|
|
snd.fm_which Set to SND_EMU2413 or SND_YM2413 depending on the FM
|
|
sound chip emulator you want to use. You can change
|
|
this and call sound_init() again for realtime switching.
|
|
|
|
snd.mixer_callback Set to NULL to use the default stream mixing routine,
|
|
or point it to your own.
|
|
|
|
Calling sound_init() will return 0 if sound emulation was disabled or an
|
|
error occured, or 1 if initialization was successful. The following
|
|
variables will be valid for use afterwards:
|
|
|
|
snd.enabled Set to 1 if sound emulation is enabled, 0 if disabled.
|
|
|
|
snd.buffer_size Size of sample buffer in bytes.
|
|
|
|
snd.sample_count Length of sample buffer in samples.
|
|
|
|
snd.stream Sound streams for the built-in mixer function or a user
|
|
supplied one to use.
|
|
|
|
snd.output Mixed audio generated by the built-in mixer function
|
|
that can be output to a sound device. Updated after each
|
|
call to system_frame().
|
|
|
|
An example of setup and use is as follows:
|
|
|
|
// Init code
|
|
snd.sample_rate = 44100;
|
|
snd.fps = 60;
|
|
snd.psg_clock = 3579545;
|
|
snd.fm_clock = 3579545;
|
|
snd.fm_which = SND_EMU2413;
|
|
snd.mixer_callback = NULL;
|
|
system_init();
|
|
|
|
// Change some parameter later on
|
|
snd.fm_which = SND_YM2413;
|
|
sound_init();
|
|
|
|
// Update code
|
|
system_frame();
|
|
osd_play_stream_stereo( snd.output, snd.buffer_size );
|
|
|
|
Custom mixing
|
|
|
|
You can provide your own mixing routine to combine audio streams. Some
|
|
uses might include:
|
|
|
|
- Per-stream volume adjustment, filtering, effects.
|
|
- Stereo output of YM2413 sound.
|
|
- Bass-boost on YM2413 rhythm output.
|
|
- Can take advantage of in-hardware playback/mixing (console ports, etc.)
|
|
|
|
There are four sound streams available:
|
|
|
|
STREAM_PSG_L SN76489 left channel output
|
|
STREAM_PSG_R SN76489 right channel output
|
|
STREAM_FM_MO YM2413 melody channel output
|
|
STREAM_FM_RO YM2413 rhythm channel output
|
|
|
|
The two YM2413 outputs are mixed together, along with the PSG output, for
|
|
a single monoaural channel in all versions of the SMS and related hardware
|
|
that support FM sound.
|
|
|
|
Synopsis of audio features by console:
|
|
|
|
FM sound Stereo PSG Output
|
|
Mark III No No Mono
|
|
Mark III+FM Yes No Mono
|
|
SMS 1 No No Mono
|
|
SMS 2 No No Mono
|
|
SMS 1 (J) Yes No Mono
|
|
Game Gear No Yes Stereo (headphone jack) Mono (speaker)
|
|
|
|
Audio from the YM2413 emulator has a lower volume than EMU2413 and will
|
|
need to be adjusted.
|
|
|
|
See the default mixer routine in 'sound.c' for an example.
|
|
|
|
----------------------------------------------------------------------------
|
|
Porting notes for earlier 0.9.x versions
|
|
----------------------------------------------------------------------------
|
|
|
|
You can check out the DOS specific code to get an idea of
|
|
how to port SMS Plus.
|
|
|
|
0.) Machine dependant issues
|
|
----------------------------
|
|
|
|
Everything should compile fine for big-endian platforms, however
|
|
I'm not sure the 8-bit pixel to 16-bit pixel conversion function
|
|
in 'render.c' is endian safe.
|
|
|
|
You need to either define or not define 'LSB_FIRST' in your makefile,
|
|
depending on your needs.
|
|
|
|
1.) Graphics
|
|
------------
|
|
|
|
The emulated display can be shown in either 8-bit or 16-bit color.
|
|
The following structure is used by the rendering routines to
|
|
draw the display, and you need to set it up prior to running the
|
|
emulation.
|
|
|
|
typedef struct
|
|
{
|
|
uint8 *data;
|
|
int width;
|
|
int height;
|
|
int pitch;
|
|
int depth;
|
|
struct
|
|
{
|
|
uint8 color[PALETTE_MAX][3];
|
|
uint8 dirty[PALETTE_MAX];
|
|
uint8 update;
|
|
}pal;
|
|
}t_bitmap;
|
|
|
|
'data' - Pointer to a linear chunk of memory. This should be at least
|
|
256x192 pixels in size. You can modify this pointer between
|
|
frames for double buffering (if it's pointed into memory mapped
|
|
video RAM), or point it to system memory so further changes
|
|
can be made. (like special effects, or for converting the
|
|
graphics data to 24 or 32-bit format)
|
|
'width' - Width of the bitmap, in pixels.
|
|
'height' - Height of the bitmap, in pixels.
|
|
'pitch' - Width of the bitmap, in *bytes*.
|
|
'depth' - Color depth. Must be 8 or 16.
|
|
'color' - An array of 32 RGB values, each scaled up to eight bits.
|
|
'dirty' - Each entry is nonzero if the color has been modified.
|
|
'update' - Nonzero if one or more colors have been modified.
|
|
|
|
If you are using 8-bit color, please note that each pixel drawn to
|
|
the bitmap uses some extra unused bits during the rendering process.
|
|
You can either mask out these bits using the PIXEL_MASK constant
|
|
from 'system.h', or set palette ranges 20-3F, 40-5F to the same
|
|
values as 00-1F.
|
|
|
|
If you are using 16-bit color, you can ignore the members of the 'pal'
|
|
structure. Remember to adjust the MAKE_PIXEL macro in 'render.h' to
|
|
whatever format your display uses. By default it will make a 16-bit
|
|
pixel in RGB 5:6:5 format.
|
|
|
|
The macros BMP_X_OFFSET, BMP_Y_OFFSET, give the offset into the
|
|
bitmap. This is because the SMS display takes up the entire bitmap,
|
|
while the GG display is centered in the middle. These macros provide
|
|
a convenient way to get the right offset.
|
|
|
|
The PALETTE_MAX constant returns the size of the palette.
|
|
This is currently set to 32 entries.
|
|
|
|
2.) Sound
|
|
---------
|
|
|
|
Sound emulation is handled through the following structure:
|
|
|
|
typedef struct
|
|
{
|
|
int fps; /* Set to 50 or 60 FPS for PAL or NTSC games */
|
|
int sample_rate; /* Set between 8000 and 48000 */
|
|
int enabled; /* 1= Init OK, 0= Sound disabled or error */
|
|
int sample_count; /* Length of buffer in samples */
|
|
int buffer_size; /* Size of buffer in bytes */
|
|
int16 *output[2]; /* Left and right channels */
|
|
} snd_t;
|
|
|
|
You must call 'system_init()' and pass the desired sample rate as an
|
|
parameter to enable sound emulation. You can set the sample rate to
|
|
zero if you do not want sound emulation. Remember that 'snd.enabled'
|
|
will be set afterwards to indicate if any errors occured.
|
|
|
|
You also must call 'system_shutdown()' when you are done running
|
|
the virtual console emulation, so some memory used by the sound
|
|
emulation code can be freed.
|
|
|
|
3.) Input
|
|
---------
|
|
|
|
Input is handled through the following structure:
|
|
|
|
typedef struct
|
|
{
|
|
int pad[2];
|
|
int system;
|
|
}t_input;
|
|
|
|
'pad[]' - Corresponds to joystick one and joystick two.
|
|
'system' - System buttons, specifically pause, start, and reset.
|
|
|
|
During each frame, you should clear members of this structure to zero,
|
|
then update each one using the INPUT_* constants in 'system.h'.
|
|
|
|
4.) Game Images
|
|
---------------
|
|
|
|
Game images are handled through the following structure:
|
|
|
|
typedef struct
|
|
{
|
|
uint8 *rom;
|
|
uint8 pages;
|
|
uint8 type;
|
|
}t_cart;
|
|
|
|
'rom' - Pointer to the ROM image.
|
|
'pages' - ROM size divided by 16k.
|
|
'type' - Set to either TYPE_SMS or TYPE_GG.
|
|
|
|
Games can be identified by their extension, which is usually '.sms'
|
|
or '.gg'. Some games have an optional 512-byte header which you must
|
|
remove. Remember to adjust the file size accordingly.
|
|
|
|
5.) Battery backed RAM
|
|
----------------------
|
|
|
|
Some game cartridges can have up to 32k of battery backed RAM present.
|
|
There are two variables relating to this:
|
|
|
|
typedef struct
|
|
{
|
|
uint8 sram[0x8000];
|
|
uint8 save;
|
|
}t_sms;
|
|
|
|
'sram' - This is the data that should be saved and loaded.
|
|
'save' - This is nonzero if the contents of sram[] should be saved.
|
|
|
|
It's impossible to know if a game will use battery backed RAM, so the
|
|
emulation code waits until a game tries to read or write it, and then
|
|
sets the 'save' flag meaning the data needs to be saved.
|
|
|
|
The basic way to deal with this is:
|
|
|
|
1. Load a game file
|
|
2. If a file with the same name, and the extension .sav exists,
|
|
then load that data into 'sram' and set the 'save' flag.
|
|
3. When exiting, check if the 'save' flag is nonzero, and if so,
|
|
write the contents of sram[] to a file with the extension .sav
|
|
and the same filename as the game file loaded.
|
|
|
|
Note that when system_reset() is called, the function 'system_load_sram'
|
|
which has a prototype in 'system.h' will be called. You *must* implement
|
|
this function. All it has to do is see if any saved battery backed RAM
|
|
is present, and update the save/sram[] members accordingly.
|
|
|
|
6.) Miscellaneous
|
|
-----------------
|
|
|
|
Before running the virtual console emulation, you can set up
|
|
these two variables:
|
|
|
|
sms.use_fm : 0= No YM2413 sound, 1= YM2413 sound
|
|
sms.country : Set to TYPE_DOMESTIC (Japan), TYPE_OVERSEAS
|
|
|
|
Some games will display different text depending on the country
|
|
setting. The default value is TYPE_OVERSEAS. This is suitable for every
|
|
country but Japan.
|
|
|
|
Some games have different music if the YM2413 sound chip is present.
|
|
If the 'fm_enable' value is set to one, then games can detect it.
|
|
|
|
If you want to use FM sound, you must ensure that 'use_fm' is nonzero
|
|
before loading a game, since this variable controls if games can detect
|
|
the YM2413 chip as well as actual YM2413 output.
|
|
|
|
Some games will only enable YM2413 sound if the country type is
|
|
also set to TYPE_DOMESTIC. One such example is Wonderboy 3.
|
|
|
|
Both of these variables are preserved when system_reset() is called.
|
|
|
|
You can call load_state/save_state to save and restore the current state
|
|
of the virtual console emulation. You need to pass a file handle as
|
|
a parameter to these functions. Therefore, you are responsible for ensuring
|
|
the file exists, and the file name. The naming convention is that all
|
|
state files are named '.st0' up to '.st9'.
|
|
|
|
7.) Function reference
|
|
----------------------
|
|
|
|
void system_init(int sound_rate);
|
|
|
|
You must set up the 'bitmap' and 'cart' structures prior to calling this
|
|
function. If you want sound emulation, pass the desired sample rate
|
|
(8000..44100). Afterwards, check the members of the 'snd' structure to see
|
|
if you can use sound emulation. You can now call system_frame() and the like.
|
|
|
|
void system_shutdown(void);
|
|
|
|
Call this when you're done with the emulation. Not terribly important
|
|
as it only frees some memory allocated by the sound emulation routines...
|
|
|
|
void system_reset(void)
|
|
|
|
Reset the virtual console emulation. This is called internally when
|
|
the INPUT_HARD_RESET flag for 'input.system' is set.
|
|
|
|
void system_load_sram(void);
|
|
|
|
Refresh the 'sms.sram[]' and 'sms.save' variables.
|
|
You must impelement this function yourself.
|
|
|
|
void system_frame(int skip);
|
|
|
|
You need to call this function 60 times a second. Pass zero as the
|
|
parameter to draw the current frame, otherwise pass one to omit
|
|
the drawing process. (ideal for frame skipping) Afterwards,
|
|
the 'bitmap' and 'snd' structures will be updated with the current
|
|
graphics and sound data. You should set up the 'input' structure
|
|
before calling this function.
|
|
|
|
8.) Example
|
|
-----------
|
|
|
|
Here's a brief overview of how to use all this:
|
|
|
|
- do machine dependant initialization (audio, video, init input, etc.)
|
|
- set up bitmap structure
|
|
- set up cart structure (load game)
|
|
- call system_init()
|
|
- if snd.enabled is set, we can use sound
|
|
- load sram data if it exists for the game
|
|
in a loop:
|
|
- update input structure based on gamepad/keyboard
|
|
- call system_frame()
|
|
- play sound using 'snd.buffer'
|
|
- copy 'bitmap.data' to the video display
|
|
- quit if needed
|
|
- save sram data if the game used it
|
|
- call system_shutdown()
|
|
|
|
9.) Other notes on porting
|
|
--------------------------
|
|
|
|
- Please read the license first.
|
|
|
|
- You must release the source code to your port in accordance with the GPL.
|
|
|
|
If you have made *no* changes to the main source code, meaning everything
|
|
in the root directory, and the cpu and dos directories, then you
|
|
do not have to include those files. No point in wasting space.
|
|
|
|
Otherwise, you must include those files with the changes clearly stated.
|
|
If the changes are the kind that could benefit other ports (like a bug
|
|
fix), then just let me know so I can update the main distribution, and
|
|
don't bother releasing those files. But let me know before you release
|
|
your port, however.
|
|
|
|
If you are using some commercial libraries to take care of items like
|
|
audio output, or if you have developed some routines which you do not want
|
|
made public (i.e. an assembly optimized blitter, or some custom joypad
|
|
polling functions), then you do not have to include those files.
|
|
|
|
I prefer it where anybody can download a port of SMS Plus and compile it
|
|
themselves, but I realize this isn't always possible.
|
|
|
|
It would be nice, and is not required, that you could organize the
|
|
source in the same way I have it set up. For instance, maintaining the
|
|
same directory structure, but adding an '/myport' directory with your
|
|
specific files, and an appropriate makefile.
|
|
|
|
- You must clearly state in the executable that you are the porter,
|
|
and that I wrote the program. Include YOUR contact information (e-mail
|
|
address, website URL). This is so users will not ask me questions on how
|
|
to use a specific port, which I know nothing about.
|
|
|
|
- You need to provide documentation. Please remember to mention
|
|
the licensing stuff pertaining to SMS Plus and the MAME code that's
|
|
mentioned (for example) in the original 'readme' I wrote. Or just
|
|
include my documentation and make some additions.
|
|
|
|
Please link to my website in the documentation, so people will know
|
|
where to get the original source code.
|