mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-24 18:21:50 +01:00
This commit is contained in:
parent
82924b00b1
commit
63f85df99c
374
docs/Genesis_ROM_Format.txt
Normal file
374
docs/Genesis_ROM_Format.txt
Normal file
@ -0,0 +1,374 @@
|
||||
|
||||
THE COMPLETE DOCUMENTATION ABOUT
|
||||
GENESIS ROM FORMAT
|
||||
|
||||
Version 1.1
|
||||
|
||||
|
||||
Release history
|
||||
^^^^^^^^^^^^^^^
|
||||
Version 1.0 (December, 1997)
|
||||
- Initial Release
|
||||
|
||||
Version 1.1 (January, 1998)
|
||||
- Splitted rom format explained!
|
||||
- New company codes
|
||||
- New errors in copyright interpreting found <sigh>
|
||||
- Month interpreting (in copyright)
|
||||
|
||||
|
||||
In this document you will find everything you need to know about
|
||||
the information embedded within a Genesis ROM. You will also find
|
||||
how to read all this information from the different ROM formats
|
||||
(BIN, SMD and MD).
|
||||
The information in this document was hacked by Volker Oth (dOnut)
|
||||
and by me with help from technical documents found on internet.
|
||||
The primary document from the internet that we used was gentech.txt.
|
||||
If you want to change this document to add any important info about
|
||||
the Genesis ROMs, do it freely but I would like to receive a copy of
|
||||
the updated document. Then, I'll add your name in it and post it on my
|
||||
homepage. Don't be a lamer and keep all names mentioned here!
|
||||
Note that all numbers with a "H" in the left are in hexadecimal, and
|
||||
the first byte of a file is the ZERO position. All information is
|
||||
provided based on the BIN file-format because of the nature of this
|
||||
format(see sections about each rom format).
|
||||
*This document should be downloaded from my homepage. Any other site
|
||||
may contain outdated material!*
|
||||
If you use this information for anything, please give the proper
|
||||
credits to the all these names listed below! I would thank you if you
|
||||
include a link to our homepages and emails, too!
|
||||
|
||||
Felipe XnaK:
|
||||
http://www.classicgaming.com/launchtool
|
||||
felipe@ComPorts.com
|
||||
Volker Oth (dOnut):
|
||||
http://members.aol.com/~volkeroth
|
||||
volkeroth@aol.com
|
||||
|
||||
|
||||
THE BASIC INFORMATION:
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
H100: 'SEGA MEGA DRIVE' 1
|
||||
H110: '(C)SEGA 1988.JUL' 2
|
||||
H120: GAME NAME (DOMESTIC) 3
|
||||
H150: GAME NAME (OVERSEAS) 4
|
||||
H180: 'XX' 5
|
||||
H182: 'XXXXXXX-XX' 6
|
||||
H18E: XXXX 7
|
||||
H190: 'XXXXXXXXXXXXXXXX' 8
|
||||
H1A0: 00000000, XXXXXXXX 9
|
||||
H1A8: RAM 10
|
||||
H1BC: MODEM DATA 11
|
||||
H1C8: MEMO 12
|
||||
H1F0: Country in which the product 13
|
||||
can be released.
|
||||
|
||||
1: This is just the console name. It can be 'SEGA MEGA DRIVE' or
|
||||
'SEGA GENESIS' depending on the console's country of origin.
|
||||
|
||||
2: Copyright notice. There SHOULD be 4 characters for the company
|
||||
code, a space and then the date in yyyy.mmm format; however, there are
|
||||
variations.
|
||||
For a listing of company codes, see "TABLE OF COMPANY CODES".
|
||||
For a listing of month abbreviations, se "TABLE OF MONTH ABBREVIATIONS".
|
||||
When the company uses a number as a company code, the copyright has
|
||||
(in most cases!) this format: '(C)T-XX 1988.JUL', where XX is the
|
||||
company code. If the company code has three digits, it should use the
|
||||
space between the code and the date.
|
||||
Some wrong copyrights i've found:
|
||||
* The year is written as '199X' or '19XX', or doen't include the
|
||||
millenium and the century.
|
||||
* The company name is '00' or 'XX'
|
||||
* Some companies that use a number for company code overwrite the
|
||||
hiphen, not the space.
|
||||
* Some companies doesn't include the '(C)' in the beginning and
|
||||
others include just their name; some just include the the year
|
||||
* Some copyrights have the year and month separated by ',','/', '-',
|
||||
space or null character (H00). I'd found one that hasn't any separator
|
||||
at all!
|
||||
-- Good luck! --
|
||||
|
||||
3: This is the so-called "Domestic game name". Is the name the game has
|
||||
in its country of origin. This field is 48 bytes long...
|
||||
|
||||
4: ... and this is the so-called "Overseas game name". This is the name
|
||||
the game has worldwide. 48 bytes long too.
|
||||
|
||||
5: Type of product. This is 2 bytes long. Known values:
|
||||
GM = Game
|
||||
Al = Education
|
||||
|
||||
6: Product code and Version number:
|
||||
* The first 7 characters are the product code
|
||||
* The 2 characters after the hiphen is the version number. This will
|
||||
vary depending on the the type of ROM or software version
|
||||
|
||||
7: Check sum, a two-bytes value (see "Calculating the Checksum")
|
||||
|
||||
8: I/0 support: (this is 16 bytes long)
|
||||
J = Joypad 4 = Team Play
|
||||
6 = 6-button Joypad 0 = Joystick for MS
|
||||
K = Keyboard R = Serial RS232C
|
||||
P = Printer T = Tablet
|
||||
B = Control Ball V = Paddle Controller
|
||||
F = Floppy Disk Drive C = CD-ROM
|
||||
L = Activator M = Mega Mouse
|
||||
|
||||
9: ROM capacity. Here you will find the start and end address of the rom,
|
||||
respectively. The start address in most cases is 0 and the end address is
|
||||
the size of rom in BYTES. Note that these values don't include the headers
|
||||
that some rom images have (discussed later). Each address is 4-bytes long.
|
||||
|
||||
10: There is a lot of information here that I can't help you with. What
|
||||
I can say is that you can get the start and end positions of the backup
|
||||
RAM at offset H1B4. Like in ROM addresses, you first acquire the start,
|
||||
then the end address. Remember, these addresses are four bytes each.
|
||||
|
||||
11: If the rom has no support for MODEM, fill this with spaces. If it has
|
||||
support for MODEM, then fill in this format: 'MOxxxxyy.z', where:
|
||||
xxxx Firm name the same as in 2
|
||||
yy MODEM NO.
|
||||
z Version
|
||||
|
||||
12: I don't know what the heck it is! But by it's name and considering
|
||||
all roms that I investigated, it seems that you can write whatever you want
|
||||
in this field...
|
||||
|
||||
13: Countries where the game can be released. What is most interesting
|
||||
here is that changing this info in some games has different behaviour.
|
||||
Streets of Rage, for example, automatically changes it's name for Bare
|
||||
Knuckle if you set the game for Japan. The "official" codes are:
|
||||
E = Europe
|
||||
J = Japan
|
||||
U = USA
|
||||
I've found some others as well(I do not guarantee this is correct!)
|
||||
A = Asia
|
||||
B = Brazil
|
||||
4 = Brazil
|
||||
F = France
|
||||
8 = Hong Kong
|
||||
This field can only contain three countries. This isn't really a
|
||||
problem because all "unofficial" codes run as Europe! Don't forget to
|
||||
set spaces to fill the bytes you don't use in this field.
|
||||
|
||||
|
||||
TABLE OF COMPANY CODES:
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This table was compiled by myself by just getting the company code
|
||||
in the ROM and writing the license that appears on the tittle screen.
|
||||
In other words, it probably contains errors and is missing a lot of
|
||||
companies.
|
||||
When two comp1anies use the same code and are different companies
|
||||
(at least to my knownledge) the names are separeted by an "or". If the
|
||||
companies are the same (like Acclain and Flying Edge), they're separated
|
||||
by a backslash (/).
|
||||
|
||||
CODE COMPANY
|
||||
|
||||
ACLD Ballistic
|
||||
ASCI Asciiware
|
||||
RSI Razorsoft
|
||||
SEGA SEGA
|
||||
TREC Treco
|
||||
TmEE Tiido's Micro Electronical Entertainment Company
|
||||
VRGN Virgin Games
|
||||
WSTN Westone
|
||||
10 Takara
|
||||
11 Taito or Accolade
|
||||
12 Capcom
|
||||
13 Data East
|
||||
14 Namco or Tengen
|
||||
15 Sunsoft
|
||||
16 Bandai
|
||||
17 Dempa
|
||||
18 Technosoft
|
||||
19 Technosoft
|
||||
20 Asmik
|
||||
22 Micronet
|
||||
23 Vic Tokai
|
||||
24 American Sammy
|
||||
29 Kyugo
|
||||
32 Wolfteam
|
||||
33 Kaneko
|
||||
35 Toaplan
|
||||
36 Tecmo
|
||||
40 Toaplan
|
||||
42 UFL Company Limited
|
||||
43 Human
|
||||
45 Game Arts
|
||||
47 Sage's Creation
|
||||
48 Tengen
|
||||
49 Renovation or Telenet
|
||||
50 Eletronic Arts
|
||||
56 Razorsoft
|
||||
58 Mentrix
|
||||
60 Victor Musical Industries
|
||||
69 Arena
|
||||
70 Virgin
|
||||
73 Soft Vision
|
||||
74 Palsoft
|
||||
76 Koei
|
||||
79 U.S. Gold
|
||||
81 Acclaim/Flying Edge
|
||||
83 Gametek
|
||||
86 Absolute
|
||||
93 Sony
|
||||
95 Konami
|
||||
97 Tradewest
|
||||
100 T*HQ Software
|
||||
101 Tecmagik
|
||||
112 Designer Software
|
||||
113 Psygnosis
|
||||
119 Accolade
|
||||
120 Code Masters
|
||||
125 Interplay
|
||||
130 Activision
|
||||
132 Shiny & Playmates
|
||||
144 Atlus
|
||||
151 Infogrames
|
||||
161 Fox Interactive
|
||||
239 Disney Interactive
|
||||
|
||||
- SPECIAL CASES:
|
||||
|
||||
In "Smurfs II" the copyright is just '(C) INFOGRAMES'
|
||||
In "Baby's day out" rom, the copyright is: '(C) T-SNK 95-FEB',
|
||||
but the company name is "HI-TECH entertainment" <sigh>
|
||||
|
||||
|
||||
TABLE OF MONTH ABBREVIATIONS:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
ABBREVIATIONS MONTH
|
||||
|
||||
JAN January
|
||||
FEB February
|
||||
MAR March
|
||||
APR or APL April
|
||||
MAY May
|
||||
JUN June
|
||||
JUL July
|
||||
AUG or 08 August
|
||||
SEP or SEPT September
|
||||
OCT October
|
||||
NOV November
|
||||
DEC December
|
||||
|
||||
|
||||
CALCULATING THE CHECKSUM:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Genesis checksum is simple enough... All you need to do is:
|
||||
1) Checksum starts as zero
|
||||
2) Skip the first 512 bytes of the ROM
|
||||
3) Read a byte from the rom and multiply its ascii value by 256, then sum
|
||||
it to the checksum
|
||||
4) Read the next byte from the rom and just sum it to the checksum
|
||||
5) If you're not in the end of file, goto step 3
|
||||
6) Get the first 16 bits from the resulting checksum and discard the higher
|
||||
bits
|
||||
7) That's your checksum!
|
||||
|
||||
|
||||
Super Magic Drive Binary file-format (.BIN):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This rom file-format is a simple rom dump. Nothing more to add!
|
||||
|
||||
|
||||
Super Magic Drive Interleaved file-format (.SMD):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is a much more complex file-format. It have a 512 bytes header
|
||||
and is interleaved in 16KB blocks. These blocks have their even bytes
|
||||
at the beginning and the odd bytes at the end of them.
|
||||
|
||||
WHAT YOU FIND IN THE 512 BYTES HEADER:
|
||||
|
||||
0: Number of blocks 1
|
||||
1: H03 *
|
||||
2: SPLIT? 2
|
||||
8: HAA *
|
||||
9: HBB *
|
||||
ALL OTHER BYTES: H00
|
||||
|
||||
1: This first byte should have the number of 16KB blocks the rom has.
|
||||
The header isn't part of the formula, so this number is:
|
||||
[size of rom-512]/16386
|
||||
If the size is more than 255, the value should be H00.
|
||||
|
||||
2: This byte indicates if the ROM is a part of a splitted rom series. If
|
||||
the rom is the last part of the series (or isn't a splitted rom at all),
|
||||
this byte should be H00. In other cases should be H40. See "CREATING
|
||||
SPLITTED ROMS" for details on this format.
|
||||
|
||||
*: Fixed values
|
||||
|
||||
|
||||
THE DE-INTERLEAVING CODE (how to convert a SMD to a BIN):
|
||||
|
||||
1) Skip the 512 bytes header
|
||||
2) Get 16KB from the ROM (16384 bytes)
|
||||
3) Decode the block
|
||||
4) Write the decoded block to the BIN file
|
||||
|
||||
DECODING A SMD BLOCK (stating byte is 0):
|
||||
|
||||
1) Get Middlepoint (8192)
|
||||
2) Get a byte from the block
|
||||
3) If the byte position is equal or smaller than middlepoint, put it
|
||||
in the first unused EVEN position of the decoded buffer
|
||||
4) If the byte position is greater than middlepoint, put it in the
|
||||
first unused ODD position of the decoded buffer
|
||||
|
||||
To convert a BIN to a SMD, just create a header (as explained before) and
|
||||
then do the reverse process!
|
||||
|
||||
|
||||
Multi Game Doctor file-format (.MD):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The MD file format also doesn't have a header. The interleaving it uses
|
||||
is equal to the SMD, but without the division in blocks! (Even bytes in
|
||||
the end of file, odd bytes in the beginning).
|
||||
|
||||
THE DECODING A MD (how to convert a MD to a BIN):
|
||||
|
||||
1) Get middlepoint ([size of rom]/2)
|
||||
2) Get a byte from the ROM
|
||||
3) If the byte position is equal or smaller than the middlepoint put the
|
||||
byte in [byte position]*2 of the destination buffer
|
||||
4) If the byte position is greater than the middlepoint, put the byte in
|
||||
([byte position]*2) - [size of rom] -1
|
||||
|
||||
|
||||
CREATING SPLITTED ROMS:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Splitted ROMs are a SMD divided into pieces. Knowing this, you may
|
||||
guess that you first need to convert your ROM to a SMD! :)
|
||||
To have a splitted ROM created all you need is divide your SMD in
|
||||
several pieces, usually all with the same size (with the exception of
|
||||
the last one). After doing that, you need to add a SMD header to all
|
||||
these pieces. About these SMD headers:
|
||||
1) The number of blocks embedded in them should be relative to the
|
||||
piece, not to the joined ROM.
|
||||
2) As stated before, with the exception of the last piece, all roms
|
||||
should have their SPLIT byte set.
|
||||
|
||||
|
||||
HOW YOU CAN HELP ME WITH THIS DOCUMENT:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Telling me the intricacies of a MGD ROM image. I never found one, but
|
||||
I do believe it's equal to MD format.
|
||||
- I'm trying to find out how the sprites are saved in Genesis ROMs. If
|
||||
you have this info, I would like to have it!
|
||||
- I never had a rom with modem support. If you have one, please test if
|
||||
the information about it is correct in this documentation (I got it from
|
||||
gentech). If you find it's correct, please explain me!!!
|
||||
|
||||
If you have any of this information, send it with your addresses (e-mail,
|
||||
homepage, etc) so I can add this to the document!
|
74
docs/REALTEC Cart Mapper - description v1.txt
Normal file
74
docs/REALTEC Cart Mapper - description v1.txt
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
REALTEC Cart Mapper - description v1 (2005.03.08)
|
||||
|
||||
by Tasco Deluxe [tascoDLX(AT)hotmail(DOT)com]
|
||||
|
||||
* Thanks to Mask Of Destiny for info about the boot state (from "The Earth Defend")
|
||||
|
||||
|
||||
The REALTEC cart mapper is found in unlicensed Genesis/MegaDrive game carts produced by REALTEC.
|
||||
Game carts known to utilize the mapper include "The Earth Defend", "Whac-A-Critter", and
|
||||
"Funnyworld/Balloon Boy 2-in-1". They all contain common code used to display the REALTEC logo
|
||||
and map a portion of the main ROM.
|
||||
|
||||
When the cart is powered on, 8KB of boot code is mapped by default into the cart's ROM area and
|
||||
is mirrored throughout. This boot code is likely the last 8KB of the main ROM (all known carts
|
||||
are 4 Mbit [512KB] w/ boot code at $07E000). The boot code, after displaying the REALTEC logo,
|
||||
has the option to display a menu for game selection. After a selection is made, any neccessary
|
||||
initializations are performed and a portion of the main ROM is mapped.
|
||||
|
||||
The code used to access the mapping registers is common amongst all known carts. A portion
|
||||
of code is copied to RAM and executed. This code writes to the mapping registers based on a
|
||||
selection number. Afterwards, the code clears the first 16 bytes of the I/O area ($A10000
|
||||
thru $A1000F) and resets the M68000 manually (stack address is read from $000000, code address
|
||||
is read from $000004).
|
||||
|
||||
The mapping is performed by writing to 3 mapped-in registers -- $400000, $402000, $404000.
|
||||
Only one value is written per register. However, the same value is written 256 times in a row.
|
||||
It is unknown whether this is because the registers explicitly require 256 writes, or because
|
||||
the hardware is so crappy as to need multiple writes.
|
||||
|
||||
The register descriptions below are listed in the order they are commonly written.
|
||||
All registers are byte-sized and only known to have write access.
|
||||
|
||||
* $402000 - Size of ROM range to map (in 1Mbit [128KB] blocks)
|
||||
|
||||
[maximum (theoretical) value of 32]
|
||||
|
||||
* $400000 - Bits of the ROM address (lower)
|
||||
|
||||
The bits (as written) are: ? ? ? ? ? c c c
|
||||
|
||||
* $404000 - Bits of the ROM address (upper)
|
||||
|
||||
The bits (as written) are: ? ? ? ? ? m m !
|
||||
|
||||
'?' is an unknown bit that is clear (in all known cases)
|
||||
'!' is an unknown bit that is set (in all known cases)
|
||||
|
||||
From the above registers, the resulting ROM address (binary) is:
|
||||
|
||||
00mm ccc0 0000 0000 0000 0000
|
||||
|
||||
The common code in all REALTEC mapper carts sets the mapper values based on a selection number
|
||||
(ROM address only -- the ROM size is fixed). The ROM addresses for these selections, numbered
|
||||
1 thru 8, are:
|
||||
|
||||
1) $000000 [$00,$01]
|
||||
2) $040000 [$02,$01]
|
||||
3) $100000 [$00,$03]
|
||||
4) $180000 [$04,$03]
|
||||
5) $200000 [$00,$05]
|
||||
6) $280000 [$04,$05]
|
||||
7) $300000 [$00,$07]
|
||||
8) $380000 [$04,$07]
|
||||
|
||||
The only cart known to use a selection other than #1 is "Funnyworld/Balloon Boy 2-in-1"
|
||||
("Balloon Boy" is #1, "Funnyworld" is #2). It is assumed that the included code is merely a
|
||||
suggestion and that any valid ROM address can be mapped.
|
||||
|
||||
A ROM range that is mapped, in order to function properly, must include a M68000 vector table
|
||||
since the cart's entire ROM area is replaced by the mapped range. None of the known carts
|
||||
attempt to remap a different ROM range after the boot code has executed. It is unknown whether
|
||||
the mapper allows the boot code to be remapped, although it seems doubtful.
|
||||
|
22
docs/changelog
Normal file
22
docs/changelog
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
[04/20/03]
|
||||
- Modified 68000 emulator to prevent 'tas.b $mem' from writing data back
|
||||
after a read (fixes Gargoyles).
|
||||
- Fixed bug in 68000 emulator to swap order of words written for address
|
||||
register indirect pre-decremented writes (fixes Jim Power graphics).
|
||||
- Added support for 240-line displays (for Super Skidmarks).
|
||||
- Rewrote part of the interrupt handling (fixes some raster effects).
|
||||
- Removed sprite collision detection code (never really worked).
|
||||
- Optimized sprite rendering inner loop.
|
||||
|
||||
[04/13/03]
|
||||
- Finished up memory map for VDP DMA V-bus reads.
|
||||
- Fixed handling of 68000 writes to I/O chip at even addresses.
|
||||
- Fixed bit 7 handling of control register in I/O chip.
|
||||
- Finished up Z80 memory map.
|
||||
- Added code to handle Genesis hardware lock-ups.
|
||||
- Removed some faulty code from the 68000 memory map handlers.
|
||||
|
||||
[03/22/03]
|
||||
- Completed implementation of Z80 banked memory handlers.
|
||||
|
235
docs/gamegenie.htm
Normal file
235
docs/gamegenie.htm
Normal file
@ -0,0 +1,235 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>GameGenie patches</TITLE>
|
||||
</HEAD>
|
||||
<BODY TEXT="#000000" BGCOLOR="#FEFEF4">
|
||||
<BASEFONT FACE="MS Sans Serif" SIZE="-1">
|
||||
|
||||
<BR>
|
||||
<CENTER><H1>GameGenie Patching</H1></CENTER>
|
||||
<BR>
|
||||
<P> GameGenie was a device created by codemasters and galoob that
|
||||
let you make cheats for games. It was plugged in the console like a normal
|
||||
cartridge, and in its top the desired cartridge was plugged. These cheats are
|
||||
possible because what GameGenie do is edit the RAM that stores values used by
|
||||
the ROMs, setting these values to a constant that can be, for example, the
|
||||
number of lifes you have!</P>
|
||||
<P> Genecyst was the first Genesis emulator to have support
|
||||
for GameGenie then, with Kgen98, Steve Snake started to use this neat feature
|
||||
in his great emulator. No ROM image of a GameGenie is necessary, as some may
|
||||
imagine, to use them with console emulators, these programs themselves have a
|
||||
built-in feature that acts like a GameGenie, writing the codes in the emulated
|
||||
RAM.</P>
|
||||
<P> The GameGenie code consists of a eight-bytes long string, and
|
||||
the valid characters are A, B, C, D, E, F, G, H, J, K, L, M, N, P, R, S, T, V,
|
||||
W, X, Y, Z, 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9, all in uppercase. Each character
|
||||
have a binary repressentation, which is 5-bits long.</P>
|
||||
|
||||
<TABLE WIDTH="70%" BORDER="0" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TH>Char</TH>
|
||||
<TH>Value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">A</TD><TD>00000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">B</TD><TD>00001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">C</TD><TD>00010</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">D</TD><TD>00011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">E</TD><TD>00100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">F</TD><TD>00101</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">G</TD><TD>00110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">H</TD><TD>00111</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">J</TD><TD>01000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">K</TD><TD>01001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">L</TD><TD>01010</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD VALIGN="TOP">
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TH>Char</TH>
|
||||
<TH>Value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">M</TD><TD>01011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">N</TD><TD>01100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">P</TD><TD>01101</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">R</TD><TD>01110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">S</TD><TD>01111</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">T</TD><TD>10000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">V</TD><TD>10001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">W</TD><TD>10010</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">X</TD><TD>10011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">Y</TD><TD>10100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">Z</TD><TD>10101</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD VALIGN="TOP">
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TH>Char</TH>
|
||||
<TH>Value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">0</TD><TD>10110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">1</TD><TD>10111</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">2</TD><TD>11000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">3</TD><TD>11001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">4</TD><TD>11010</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">5</TD><TD>11011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">6</TD><TD>11100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">7</TD><TD>11101</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">8</TD><TD>11110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">9</TD><TD>11111</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<BR>
|
||||
<P> The cheat code should be firstly converted directly using the
|
||||
table above, and then the bits should be reordered. For example, the GameGenie
|
||||
code SCRA-BJX0 is translated to:</P>
|
||||
<FONT FACE="Courier">
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Code:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Bits:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Id:</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>S</TD><TD>C</TD><TD>R</TD><TD>A</TD>
|
||||
</TR>
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>01111</TD><TD>00010</TD><TD>01110</TD><TD>00000</TD>
|
||||
</TR>
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>ijklm</TD><TD>nopIJ</TD><TD>KLMNO</TD><TD>PABCD</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">-</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">-</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">-</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR ALIGN="CENTER"><TD>B</TD><TD>J</TD><TD>X</TD><TD>0</TD></TR>
|
||||
<TR ALIGN="CENTER"><TD>00001</TD><TD>01000</TD><TD>10011</TD><TD>10110</TD></TR>
|
||||
<TR ALIGN="CENTER"><TD>EFGHd</TD><TD>efgha</TD><TD>bcQRS</TD><TD>TUVWX</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</FONT>
|
||||
<P> Then rearrange (using the id) as...</P>
|
||||
<FONT FACE="Courier">
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Bits:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Id:</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>00000000</TD><TD>10011100</TD><TD>01110110</TD>
|
||||
</TR>
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>ABCDEFGH</TD><TD>IJKLMNOP</TD><TD>QRSTUVWX</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">:</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1">
|
||||
<TR ALIGN="CENTER"><TD>01010100</TD> <TD>01111000</TD></TR>
|
||||
<TR ALIGN="CENTER"><TD>abcdefgh</TD><TD>ijklmnop</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</FONT>
|
||||
<BR>
|
||||
<P> Which give us, in hexa, <B>009C76:5478</B>. This means that
|
||||
<B>H5478</B> will be written at <B>H009C76</B> memory offset.</P>
|
||||
</BODY>
|
||||
</HTML>
|
715
docs/gen-hw.txt
Normal file
715
docs/gen-hw.txt
Normal file
@ -0,0 +1,715 @@
|
||||
|
||||
Sega Genesis hardware notes
|
||||
Version 0.8 (03/02/01)
|
||||
|
||||
by Charles MacDonald
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Unpublished work Copyright 2000, 2001 Charles MacDonald
|
||||
|
||||
Here is a compilation of some notes I've written up on the Sega Genesis
|
||||
hardware. Everything described herein has been checked on the real thing,
|
||||
though that doesn't necessarily mean my testing methods were flawless. :)
|
||||
|
||||
Version history
|
||||
---------------
|
||||
[0.8]
|
||||
- Added information on the SVP chip used in Virtua Racing. (section 4.2)
|
||||
- Added information on EEPROM storage. (section 4.1)
|
||||
- Changed miscellaneous section around.
|
||||
[0.7]
|
||||
- Added more information about access to the Z80 bus. (section 2.2)
|
||||
- Updated the VDP register information, and removed some things
|
||||
that were specific to VDP programming. (section 1.1)
|
||||
- Added some background about the PSG. (section 4)
|
||||
[0.6]
|
||||
- Rewrote the 68000 memory map description. (section 1)
|
||||
- Rewrote the Z80 memory map description. (section 2.1)
|
||||
- Added memory access section. (section 1.2)
|
||||
- Added a few miscellaneous topics. (section 4)
|
||||
[0.5]
|
||||
- Added more Z80 banking information.
|
||||
- Added unused VDP address return values from the Z80 side.
|
||||
- Added example of how to start up the Z80 on power-up.
|
||||
- Added information on Phantasy Star 4 from Jeff Quinn.
|
||||
- Added list of consoles that support Mark-III compatibility mode.
|
||||
- Fixed a few typos.
|
||||
[0.4]
|
||||
- Added more details on 68000 and Z80 memory map.
|
||||
- Added more information on VDP addresses.
|
||||
- Added some thoughts on Phantasy Star 4.
|
||||
[0.3]
|
||||
- Added more information on I/O registers. (section 3)
|
||||
- Fixed a few typos pointed out by Tim Meekins.
|
||||
[0.2]
|
||||
- Added section on I/O port programming and gamepads
|
||||
[0.1]
|
||||
- Initial release
|
||||
|
||||
Table of Contents
|
||||
|
||||
1.) 68000 memory map
|
||||
1.1) VDP registers
|
||||
1.2) Memory access quirks
|
||||
1.3) Clock speeds
|
||||
2.) Sound hardware overview
|
||||
2.1) Z80 memory map
|
||||
2.2) RESET and BUSREQ registers
|
||||
2.3) Banking
|
||||
2.4) Interrupts
|
||||
3.) Input and Output
|
||||
3.1) Programming I/O ports
|
||||
3.2) Gamepad specifics
|
||||
4.) Miscellaneous
|
||||
4.1) EEPROM
|
||||
4.2) Virtua Racing
|
||||
4.3) Phantasy Star 4
|
||||
4.4) Other topics
|
||||
5.) Credits
|
||||
6.) Disclaimer
|
||||
|
||||
|
||||
1.) 68000 memory map
|
||||
|
||||
000000-3FFFFFh : ROM
|
||||
400000-7FFFFFh : Unused (1)
|
||||
800000-9FFFFFh : Unused (2)
|
||||
A00000-A0FFFFh : Z80 address space (3)
|
||||
A10000-A1001Fh : I/O
|
||||
A10020-BFFFFFh : Internal registers and expansion (4)
|
||||
C00000-DFFFFFh : VDP (5)
|
||||
E00000-FFFFFFh : RAM (6)
|
||||
|
||||
1. Reads return the MSB of the next instruction to be fetched, with the
|
||||
LSB set to zero. Writes do nothing.
|
||||
|
||||
2. Reading or writing any address will lock up the machine.
|
||||
This area is used for the 32X adapter.
|
||||
|
||||
3. Addresses A08000-A0FFFFh mirror A00000-A07FFFh, so the 68000 cannot
|
||||
access it's own banked memory. All addresses are valid except for
|
||||
the VDP which is at A07F00-A07FFFh and A0FF00-A0FFFFh, writing or
|
||||
reading those addresses will lock up the machine.
|
||||
|
||||
4. Reading some addresses lock up the machine, others return the MSB
|
||||
of the next instruction to be fetched with the LSB is set to zero.
|
||||
|
||||
The latter applies when reading A11100h (except for bit 0 reflects
|
||||
the state of the bus request) and A11200h.
|
||||
|
||||
Valid addresses in this area change depending on the peripherals
|
||||
and cartridges being used; the 32X, Sega CD, and games like Super
|
||||
Street Fighter II and Phantasy Star 4 use addresses within this range.
|
||||
|
||||
5. The VDP is mirrored at certain locations from C00000h to DFFFFFh. In
|
||||
order to explain what addresses are valid, here is a layout of each
|
||||
address bit:
|
||||
|
||||
MSB LSB
|
||||
110n n000 nnnn nnnn 000m mmmm
|
||||
|
||||
'1' - This bit must be 1.
|
||||
'0' - This bit must be 0.
|
||||
'n' - This bit can have any value.
|
||||
'm' - VDP addresses (00-1Fh)
|
||||
|
||||
For example, you could read the status port at D8FF04h or C0A508h,
|
||||
but not D00084h or CF00008h. Accessing invalid addresses will
|
||||
lock up the machine.
|
||||
|
||||
6. The RAM is 64K in size and is repeatedly mirrored throughout the entire
|
||||
range it appears in. Most games only access it at FF0000-FFFFFFh.
|
||||
|
||||
1.1) VDP registers
|
||||
|
||||
The lower five bits of the address specify what memory mapped VDP register
|
||||
to access:
|
||||
|
||||
00h : Data port
|
||||
02h : Data port
|
||||
04h : Control port (1)
|
||||
06h : Control port
|
||||
08h : HV counter (2)
|
||||
0Ah : HV counter
|
||||
0Ch : HV counter
|
||||
0Eh : HV counter
|
||||
11h : SN76489 PSG (3)
|
||||
13h : SN76489 PSG
|
||||
15h : SN76489 PSG
|
||||
17h : SN76489 PSG
|
||||
18h : Unused (4)
|
||||
1Ah : Unused
|
||||
1Ch : Unused
|
||||
1Eh : Unused
|
||||
|
||||
1. For reads, the upper six bits of the status flags are set to the
|
||||
value of the next instruction to be fetched. Bit 6 is always zero.
|
||||
For example:
|
||||
|
||||
move.w $C00004, d0 ; Next word is $4E71
|
||||
nop ; d0 = -1-- 11?? ?0?? ????
|
||||
|
||||
When reading the status flags through the Z80's banked memory area,
|
||||
the upper six bits are set to one.
|
||||
|
||||
2. Writing to the HV counter will cause the machine to lock up.
|
||||
|
||||
3. Reading the PSG addresses will cause the machine to lock up.
|
||||
|
||||
Doing byte-wide writes to even PSG addresses has no effect.
|
||||
|
||||
If you want to write to the PSG via word-wide writes, the data
|
||||
must be in the LSB. For instance:
|
||||
|
||||
move.b (a4)+, d0 ; PSG data in LSB
|
||||
move.w d0, $C00010 ; Write to PSG
|
||||
|
||||
4. Reading the unused addresses returns the next instruction to be fetched.
|
||||
For example:
|
||||
|
||||
move.w $C00018, d0 ; Next word is $4E71
|
||||
nop ; d0 = $4E71
|
||||
|
||||
When reading these addresses through the Z80's banked memory area,
|
||||
the value returned is always FFh.
|
||||
|
||||
Writing to C00018h and C0001Ah has no effect.
|
||||
|
||||
Writing to C0001Ch and C0001Eh seem to corrupt the internal state
|
||||
of the VDP. Here's what each bit does: (assuming word-wide writes)
|
||||
|
||||
8E9Fh : These bits cause brief flicker in the current 8 pixels
|
||||
being drawn when the write occurs.
|
||||
|
||||
5040h : These bits blank the display like bit 6 of register #1 when set.
|
||||
|
||||
2000h : This bit makes every line show the same random garbage data.
|
||||
|
||||
0100h : This bit makes random pattern data appear in the upper eight
|
||||
and lower ten lines of the display, with the normal 224 lines
|
||||
in the middle untouched. For those of you interested, the
|
||||
display is built up like so:
|
||||
|
||||
224 lines for the active display
|
||||
10 lines unused (can show pattern data here with above bit)
|
||||
3 lines vertical blank (no border color shown)
|
||||
3 lines vertical retrace (no picture shown at all)
|
||||
13 lines vertical blank (no border color shown)
|
||||
8 lines unused (can show pattern data here with above bit)
|
||||
|
||||
I know that comes up to 261 lines and not 262. But that's
|
||||
all my monitor shows.
|
||||
|
||||
Turning the display off makes the screen roll vertically,
|
||||
and random pattern data is displayed in all lines when
|
||||
this bit is set.
|
||||
|
||||
0020h : This bit causes the name table and pattern data shown to
|
||||
become corrupt. Not sure if the VRAM is bad or the VDP is
|
||||
just showing the wrong data.
|
||||
|
||||
1.2) Memory access quirks
|
||||
|
||||
Byte-wide writes
|
||||
|
||||
Writing to the VDP control or data ports is interpreted as a 16-bit
|
||||
write, with the LSB duplicated in the MSB. This is regardless of writing
|
||||
to an even or odd address:
|
||||
|
||||
move.w #$A5, $C00003 ; Same as 'move.w #$A5A5, $C00002'
|
||||
move.w #$87, $C00004 ; Same as 'move.w #$8787, $C00004'
|
||||
|
||||
Byte-wide reads
|
||||
|
||||
Reading from even VDP addresses returns the MSB of the 16-bit data,
|
||||
and reading from odd address returns the LSB:
|
||||
|
||||
move.b $C00008, d0 ; D0 = V counter
|
||||
move.b $C00001, d0 ; D0 = LSB of current VDP data word
|
||||
move.b $C0001F, d0 ; D0 = $71
|
||||
nop
|
||||
move.b $C00004, d0 ; D0 = MSB of status flags
|
||||
|
||||
Word-wide writes
|
||||
|
||||
When doing word-wide writes to Z80 RAM, only the MSB is written, and
|
||||
the LSB is ignored:
|
||||
|
||||
0000: AA BB CC DD ; Z80 memory
|
||||
move.w #$1234, $A00000 ; do a word-wide write
|
||||
0000: 12 BB CC DD ; result
|
||||
|
||||
Word-wide reads
|
||||
|
||||
A word-wide read from Z80 RAM has the LSB of the data duplicated in the MSB.
|
||||
|
||||
0000: AA BB CC DD ; Z80 memory
|
||||
move.w $A00000, d0 ; do a word-wide read
|
||||
d0 = $AAAA ; result
|
||||
|
||||
1.3) Clock speeds
|
||||
|
||||
These are for an NTSC Sega Genesis console.
|
||||
|
||||
680000 = 7.67 MHz
|
||||
YM2612 = 7.67 MHz
|
||||
Z80 = 3.58 MHz
|
||||
SN76489 = 3.58 MHz
|
||||
|
||||
If anyone has information about timing for PAL consoles, please let me know.
|
||||
|
||||
2) Sound hardware overview
|
||||
|
||||
The following components used for sound generation:
|
||||
|
||||
- Zilog Z80 CPU
|
||||
- 8k static RAM
|
||||
- Yamaha YM2612 FM sound generator
|
||||
- SN76489 PSG
|
||||
|
||||
2.1) Z80 memory map
|
||||
|
||||
0000-1FFFh : RAM
|
||||
2000-3FFFh : RAM (mirror)
|
||||
4000-5FFFh : YM2612 (1)
|
||||
6000-60FFh : Bank address register (2)
|
||||
6100-7EFFh : Unused (3)
|
||||
7F00-7FFFh : VDP (4)
|
||||
8000-FFFFh : Bank area
|
||||
|
||||
1. The YM2612 has two address lines, so it is available at 4000-4003h and
|
||||
is mirrored repeatedly up to 5FFFh.
|
||||
|
||||
2. Writes go to the bank address register, reads return FFh.
|
||||
The value returned applies to both the 68000 and Z80.
|
||||
|
||||
3. Writes are ignored, reads return FFh.
|
||||
The value returned applies to both the 68000 and Z80.
|
||||
|
||||
4. Only addresses 7F00-7F1Fh are valid, writes to 7F20-7FFFh will
|
||||
lock up the machine.
|
||||
|
||||
Z80 access to the VDP has the same results as doing byte-wide reads
|
||||
and writes as described in section 1.2. So only the HV counter and
|
||||
PSG can be used effectively.
|
||||
|
||||
All I/O ports return FFh, and writing to them has no effect. The Thunder
|
||||
Force games read port BFh in the IRQ subroutine, this would appear to be
|
||||
a misunderstanding on the programmer's behalf.
|
||||
|
||||
The 68000 can write to A06000h to set up the bank address.
|
||||
|
||||
2.2) RESET and BUSREQ registers
|
||||
|
||||
Bit 0 of A11100h (byte access) or bit 8 of A11100h (word access) controls
|
||||
the Z80's /BUSREQ line.
|
||||
|
||||
Writing 1 to this bit will request the Z80 bus. You can then release
|
||||
the bus later on by writing 0.
|
||||
|
||||
Reading this bit will return 0 if the bus can be accessed by the 68000,
|
||||
or 1 if the Z80 is still busy.
|
||||
|
||||
If the Z80 is reset, or if it is running (meaning the 68000 does not
|
||||
have the bus) it will also return 1. The only time it will switch from
|
||||
1 to 0 is right after the bus is requested, and if the Z80 is still
|
||||
busy accessing memory or not.
|
||||
|
||||
Bit 0 of A11200h (byte access) or bit 8 of A11200h (word access) controls
|
||||
the Z80's /RESET line.
|
||||
|
||||
Writing 0 to this bit will start the reset process. The Z80 manual says you
|
||||
have to assert the /RESET line for three Z80 clock cycles as a reset does
|
||||
not happen instantly.
|
||||
|
||||
Writing 1 to this bit will stop the reset process. At this point, the Z80
|
||||
will start executing from address 0000h onwards.
|
||||
|
||||
The /RESET line is shared with the YM2612. For as long as the Z80 is reset,
|
||||
the YM2612 cannot be used.
|
||||
|
||||
The Z80 bus can only be accessed by the 68000 when the Z80 is running
|
||||
and the 68000 has the bus. (as opposed to the Z80 being reset, and/or
|
||||
having the bus itself)
|
||||
|
||||
Otherwise, reading $A00000-A0FFFF will return the MSB of the next
|
||||
instruction to be fetched, and the LSB will be set to zero. Writes
|
||||
are ignored. This even applies to the VDP area that would normally
|
||||
lock up the machine.
|
||||
|
||||
Interestingly enough, you can still access $A10000-A1001F during this
|
||||
time, which seems to be contradictory to some documentation which says
|
||||
you can only access the I/O region when the 68000 has the bus.
|
||||
|
||||
On power-up, the Z80 will be reset and will have the bus.
|
||||
If you want to load a Z80 program and run it, do the following:
|
||||
|
||||
- Stop the reset process
|
||||
- Request bus
|
||||
- Load Z80 program
|
||||
- Start the reset process
|
||||
- Release bus
|
||||
- Stop the reset process
|
||||
|
||||
2.3) Banking
|
||||
|
||||
The Z80 can access the 68000's address space through a banking mechanism
|
||||
which maps 32k pages to 8000-FFFFh on the Z80 side.
|
||||
|
||||
Most games do this to get at large data chunks like YM2612 DAC samples.
|
||||
However, you can access anything else the 68000 can. (I've tried reading
|
||||
the version register and setting the VDP border color this way with
|
||||
success - in fact some 32X sample code shows the PWM sound generator
|
||||
programmed by the Z80 through banking)
|
||||
|
||||
To specify which 32k section you want to access, write the upper nine
|
||||
bits of the complete 24-bit address into bit 0 of the bank address
|
||||
register, which is at 6000h (Z80) or A06000h (68000), starting with
|
||||
bit 15 and ending with bit 23.
|
||||
|
||||
For example:
|
||||
|
||||
ld ix, $6000 ;
|
||||
xor a ;
|
||||
ld (ix), a ; Bit 15 = 0
|
||||
ld (ix), a ; Bit 16 = 0
|
||||
ld (ix), a ; Bit 17 = 0
|
||||
ld (ix), a ; Bit 18 = 0
|
||||
ld (ix), a ; Bit 19 = 0
|
||||
ld (ix), a ; Bit 20 = 0
|
||||
ld (ix), a ; Bit 21 = 0
|
||||
inc a ;
|
||||
ld (ix), a ; Bit 22 = 1
|
||||
ld (ix), a ; Bit 23 = 1
|
||||
|
||||
After this routine executes, Z80 addresses 8000-FFFFh now correspond
|
||||
to 68000 addresses C00000-C07FFFh.
|
||||
|
||||
In my own tests, I've been unable to do the following:
|
||||
|
||||
- Read banked 68000 RAM. (returns FFh)
|
||||
- Find result of partial writes to the bank address register.
|
||||
- Have the Z80 read A00000-A0FFFF through the banked memory area.
|
||||
(locks up the machine)
|
||||
|
||||
Steve Snake informed me that reading 68000 RAM is possible, but is not
|
||||
a recommended practice by Sega. Perhaps only some models of the Genesis
|
||||
allow for it.
|
||||
|
||||
2.4) Interrupts
|
||||
|
||||
The Z80 runs in interrupt mode 1, where an interrupt causes a RST 38h.
|
||||
However, interrupt mode 0 can be used as well, since FFh will be read
|
||||
off the bus.
|
||||
|
||||
The Z80 will recieve an IRQ from the VDP on scanline E0h. This happens
|
||||
once per frame, every frame, regardless of frame interrupts being
|
||||
disabled by the 68000.
|
||||
|
||||
If the Z80 has interrupts disabled when the frame interrupt is supposed
|
||||
to occur, it will be missed, rather than made pending.
|
||||
|
||||
There is no way to trigger an NMI unless the Genesis has been switched
|
||||
into Mark 3 compatability mode, and this only means the NMI line is
|
||||
mapped to the cartridge port, it's not controllable through software.
|
||||
|
||||
3.0) Input and Output
|
||||
|
||||
The Genesis has three general purpose I/O ports. Devices like gamepads,
|
||||
modems, light guns, etc. can be used with them.
|
||||
|
||||
Here's a read-out of the I/O registers in their default state. Each
|
||||
one can be read at an even address (e.g. A1000Dh == A1000Ch) as well.
|
||||
|
||||
A10001h = A0 Version register
|
||||
|
||||
A10003h = 7F Data register for port A
|
||||
A10005h = 7F Data register for port B
|
||||
A10007h = 7F Data register for port C
|
||||
|
||||
A10009h = 00 Ctrl register for port A
|
||||
A1000Bh = 00 Ctrl register for port B
|
||||
A1000Dh = 00 Ctrl register for port C
|
||||
|
||||
A1000Fh = FF TxData register for port A
|
||||
A10011h = 00 RxData register for port A
|
||||
A10013h = 00 S-Ctrl register for port A
|
||||
|
||||
A10015h = FF TxData register for port B
|
||||
A10017h = 00 RxData register for port B
|
||||
A10019h = 00 S-Ctrl register for port B
|
||||
|
||||
A1001Bh = FF TxData register for port C
|
||||
A1001Dh = 00 RxData register for port C
|
||||
A1001Fh = 00 S-Ctrl register for port C
|
||||
|
||||
Bit 7 of the Data registers can be read or written.
|
||||
Any bit that is set as an input will return '1'.
|
||||
Any bit that is set as an output will return the value last written.
|
||||
|
||||
Bits 7-0 of the Ctrl registers can be read or written.
|
||||
|
||||
Bits 7-0 of the TxData registers can be read or written.
|
||||
|
||||
The RxData register will always return zero.
|
||||
|
||||
Bits 7-4 of the S-Ctrl registers can be read or written.
|
||||
|
||||
3.1) Programming I/O ports
|
||||
|
||||
In the context of this description, I'll assume the device plugged in is a
|
||||
gamepad. However, other periperhals like multi-taps, modems, mice, light
|
||||
guns, etc, exist.
|
||||
|
||||
Here's a pin-out of the connector:
|
||||
|
||||
Pin 1 - UP
|
||||
Pin 2 - DOWN
|
||||
Pin 3 - LEFT
|
||||
Pin 4 - RIGHT
|
||||
Pin 5 - Vcc
|
||||
Pin 6 - TL
|
||||
Pin 7 - TH
|
||||
Pin 8 - GND
|
||||
Pin 9 - TR
|
||||
|
||||
Each I/O port has several associated registers. I'll only cover the
|
||||
data and control registers, as the others are used for serial and
|
||||
parallel communication.
|
||||
|
||||
The data register corresponds to the I/O port pins like so:
|
||||
|
||||
Bit 7 - (Not connected)
|
||||
Bit 6 - TH
|
||||
Bit 5 - TL
|
||||
Bit 4 - TR
|
||||
Bit 3 - RIGHT
|
||||
Bit 2 - LEFT
|
||||
Bit 1 - DOWN
|
||||
Bit 0 - UP
|
||||
|
||||
A '0' means a button has been pressed, and '1' means a button has been
|
||||
released.
|
||||
|
||||
Bit 7 isn't connected to any pin on the I/O port. It will latch a value
|
||||
written to it, as shown:
|
||||
|
||||
move.b $A10003, d0 ; D0 = $7F
|
||||
move.b #$80, $A10003 ; Bit 7 = 1
|
||||
move.b $A10003, d0 ; D0 = $FF
|
||||
move.b #$00, $A10003 ; Bit 7 = 0
|
||||
move.b $A10003, d0 ; D0 = $7F
|
||||
|
||||
Bits 6-0 of the control register define what bits of the data register
|
||||
are inputs or outputs. Gamepads use TH as an output and the remaining
|
||||
pins as input, so a value of $40 would be written to the control register.
|
||||
|
||||
3.2) Gamepad specifics
|
||||
|
||||
A gamepad maps the directional pad to the pins mentioned earlier
|
||||
(left, right, up, down), and multiplexes the four buttons (A, B, C, Start)
|
||||
through the TL and TR pins.
|
||||
|
||||
The TH pin controls which pairs of buttons (either A, Start or C, B) are
|
||||
output through TL and TR by the multiplexer chip.
|
||||
|
||||
In order to read all the buttons, A program will set TH = 1, read the data
|
||||
port, set TH = 0, and read the port again. The data returned is as follows:
|
||||
|
||||
TH = 0 : ?0SA00DU
|
||||
TH = 1 : ?1CBRLDU
|
||||
|
||||
? = Whatever was last written to bit 7.
|
||||
S = Start
|
||||
A = Button A
|
||||
B = Button B
|
||||
C = Button C
|
||||
U = Up
|
||||
D = Down
|
||||
L = Left
|
||||
R = Right
|
||||
|
||||
A 6-button gamepad allows the extra buttons to be read based on how
|
||||
many times TH is switched from 1 to 0 (and not 0 to 1). Observe the
|
||||
following sequence:
|
||||
|
||||
TH = 1 : ?1CBRLDU 3-button pad return value
|
||||
TH = 0 : ?0SA00DU 3-button pad return value
|
||||
TH = 1 : ?1CBRLDU 3-button pad return value
|
||||
TH = 0 : ?0SA0000 D3-0 are forced to '0'
|
||||
TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0
|
||||
TH = 0 : ?0SA1111 D3-0 are forced to '1'
|
||||
|
||||
M = Mode
|
||||
X = Button X
|
||||
Y = Button Y
|
||||
Z = Button Z
|
||||
|
||||
From this point on, the standard 3-button pad values will be returned
|
||||
if any further TH transitions are done.
|
||||
|
||||
If TH isn't modified in about 8192 (probably less than that) 68000 CPU
|
||||
cycles, a 'time-out' will occur and the sequence to read 6-button values
|
||||
can be done again. Games usually poll the gamepad once per frame,
|
||||
which is always enough for the time-out to occur.
|
||||
|
||||
I believe checking if D3-D0 are all set or clear (as shown in the list
|
||||
above) would be another method to verify if 6-button or 3-button pad data
|
||||
was being returned.
|
||||
|
||||
Some games may access the gamepad in a way that causes 6-button values
|
||||
to be returned when 3-button values are expected. To get around this,
|
||||
the MODE button can be held down when powering-up the console, and
|
||||
the 6-button gamepad will respond like a 3-button one.
|
||||
|
||||
4.) Miscellaneous
|
||||
|
||||
The following are miscellaneous topics.
|
||||
|
||||
4.1) EEPROM
|
||||
|
||||
Some cartridges use a Xicor X24C01 EEPROM chip. The chip is programmed
|
||||
in a serial fashion (it has only two wires), and has 128 8-bit bytes
|
||||
of storage.
|
||||
|
||||
Games using EEPROM have the backup data string at offset $1B0 in the
|
||||
cartridge header area formatted like so:
|
||||
|
||||
0001B0: 52 41 E8 40 00 20 00 01 00 20 00 01
|
||||
|
||||
The Sega manual describes how the above data should be interpreted.
|
||||
In this case, it corresponds to a device mapped to odd memory addresses,
|
||||
occupying the byte at $200001.
|
||||
|
||||
The only games I know of which use an EEPROM chip are:
|
||||
|
||||
- Wonderboy 3 / Monster World IV
|
||||
- Rockman Megaworld
|
||||
- Megaman: The Wily Wars
|
||||
|
||||
4.2) Virtua Racing
|
||||
|
||||
The Virtua Racing cartridge has 2MB ROM, 128K RAM, and a custom DSP chip
|
||||
called the 'Sega Virtua Processor' (SVP), which is manufactured by Sega.
|
||||
To the best of my knowledge, the SVP chip has internal ROM and possibly
|
||||
internal RAM.
|
||||
|
||||
The main purpose of the SVP is to render polygons as 8x8 patterns, which
|
||||
the game program transfers to VRAM from the 128K RAM area using DMA.
|
||||
|
||||
The VR cartridge has the following memory map:
|
||||
|
||||
000000-1FFFFFh : Program ROM (2MB)
|
||||
200000-2FFFFFh : Unused
|
||||
300000-31FFFFh : On-cart RAM (128K)
|
||||
320000-3FFFFFh : (?)
|
||||
390000-39FFFFh : (?)
|
||||
3A0000-3AFFFFh : (?)
|
||||
|
||||
The SVP chip has registers mapped in the I/O space:
|
||||
|
||||
A15000.w - Can read and write commands
|
||||
A15005.b - Reading bit 0 acts like a status flag (SVP busy?)
|
||||
A15006.w - Unknown ($0000, $0001, $000A written)
|
||||
A15008.w - Unknown ($0000, $0001, $0000 written)
|
||||
|
||||
Commands are two bytes in size, and are read and written to A15000h.
|
||||
|
||||
FFFFh - Command reset (?) (done before any access)
|
||||
'SV' - Command init (?) (written before SVP communication)
|
||||
'OK' - Command OK (?) (written after 'SV')
|
||||
'Tx' - Where 'x' equals the following value based on the command
|
||||
selected in the test menu:
|
||||
0 - "DSP ROM RD" and
|
||||
"DSP RAM OVER WRITE"
|
||||
1 - "DSP DRAM R/W"
|
||||
2 - "DSP IRAM R/W"
|
||||
4 - "DSP POINTER"
|
||||
|
||||
To emulate the SVP chip, somebody needs to figure out how to dump the
|
||||
internal ROM (the test menu shows that it has a DSP ROM reading option,
|
||||
perhaps sending a certain command to the SVP makes it map it's internal
|
||||
ROM within the $300000-$3FFFFF area) and figure out how the DSP works.
|
||||
|
||||
All of the above information came from physically examining a VR cartridge,
|
||||
and from disassembling the test menu code. (found at $1B000 for those
|
||||
of you who are interested)
|
||||
|
||||
4.3) Phantasy Star 4
|
||||
|
||||
Phantasy Star 4 is a 24 megabit game with 16k of battery backed RAM
|
||||
mapped to $200001-$203FFF. (odd addresses used) It has ROM in the same
|
||||
area where the RAM is. I've observed that the game will always write
|
||||
$01 to $A130F1 before accessing the RAM, and then write $00 when
|
||||
done. It could be that bit 0 of $A130F1 controls ROM/RAM banking at
|
||||
that location.
|
||||
|
||||
Jeff Quinn has tested this and confirmed it to work, and also reported
|
||||
an area of the game where supporting banked SRAM is important; when
|
||||
your characters encounter a GEROTLUX below the town of Tyler on Dezolis,
|
||||
the game will try to access the ROM data that is obscured by SRAM.
|
||||
|
||||
4.4) Other topics
|
||||
|
||||
- The 68000 RESET instruction has no effect.
|
||||
|
||||
- If the VDP is not accessed often enough, it will (appear) to lock up.
|
||||
I'm not sure what the cause is, but any control port access is enough
|
||||
to keep it going. Maybe some of the internal VDP memory is composed
|
||||
of DRAM cells that lose their data after a while. This happens in
|
||||
the Mark III compatability mode as well as mode 4 and mode 5.
|
||||
|
||||
- The status of the YM2612 can be read at any of it's four addresses.
|
||||
Since only address zero is documented as valid, it could be that the
|
||||
other addresses may return an incorrect result in some situations.
|
||||
|
||||
- The PSG is compatible with the Texas Instruments SN76489. It is actually
|
||||
on the same physical chip as the VDP, and it's output comes directly
|
||||
out of the VDP to be mixed with the YM2612. Sega did the same thing
|
||||
with the System C2 (possibly System 18) and SMS VDPs as well.
|
||||
|
||||
Can anyone contribute some information about the Genesis security
|
||||
and operating system ROM features? I know of a few:
|
||||
|
||||
- Games must write the text 'SEGA' to A14000h if the lower four
|
||||
bits of the version register return 01h.
|
||||
- Writing 01h to A14101h disables the OS ROM and swaps in the cart ROM.
|
||||
- The OS ROM checks for 'SEGA' or ' SEGA' at offset 100h in the cart ROM.
|
||||
|
||||
Here's a list of consoles that support the Mark III compatability mode.
|
||||
|
||||
- Sega Mega Drive
|
||||
- Sega Mega Drive 2
|
||||
- Sega Genesis
|
||||
- Sega Genesis 2
|
||||
|
||||
And ones that do not:
|
||||
|
||||
- Genesis 3 (Majesco)
|
||||
|
||||
If anyone has tested this with the Nomad, CDX, MegaJet, etc., please
|
||||
let me know.
|
||||
|
||||
5.) Credits
|
||||
|
||||
I would like to thank the following people for contributing information:
|
||||
|
||||
Bart Trzynadlowski, Christian Schiller, Flavio Morsoletto, Jeff Quinn,
|
||||
Mike Gordon, Naflign, Omar Cornut, Steve Snake, and Tim Meekins.
|
||||
|
||||
Contributors to the Sega Programming FAQ.
|
||||
Gringoz for the Genesis schematics.
|
||||
|
||||
6.) Disclaimer
|
||||
|
||||
If you use any information from this document, please credit me
|
||||
(Charles MacDonald) and optionally provide a link to my webpage
|
||||
(http://cgfm2.emuviews.com/) so interested parties can access it.
|
||||
|
||||
The credit text should be present in the accompanying documentation of
|
||||
whatever project which used the information, or even in the program
|
||||
itself (e.g. an about box)
|
||||
|
||||
Regarding distribution, you cannot put this document on another
|
||||
website, nor link directly to it.
|
||||
|
BIN
docs/gen_eeprom.doc
Normal file
BIN
docs/gen_eeprom.doc
Normal file
Binary file not shown.
458
docs/gennotes.txt
Normal file
458
docs/gennotes.txt
Normal file
@ -0,0 +1,458 @@
|
||||
******************************************************
|
||||
* Sega Genesis Technical Notes by Bart Trzynadlowski *
|
||||
* and many others! *
|
||||
******************************************************
|
||||
|
||||
|
||||
Second Edition: February 7, 2000
|
||||
- Current
|
||||
- Made a table of contents
|
||||
- Added tile information and Scroll layer name table information
|
||||
- Added info on Genesis security system and "do nots" courtesy of
|
||||
Flavio. He also found a mistake in the joypad notes.
|
||||
- Added SMD ROM stuff
|
||||
First Edition: February 3, 2000
|
||||
- Initial release
|
||||
|
||||
|
||||
This document is intended to be used as a reference alongside sega2.doc or any
|
||||
other complete Sega Genesis technical documentation, it is not intended as a
|
||||
standalone resource for learning about the Sega Genesis game console.
|
||||
There is also some information here pertaining to specific situations
|
||||
such as using the Starscream 68000 CPU core in an emulator project.
|
||||
I wrote this document while working on a Genesis emulator. I felt some
|
||||
things needed more description than was available. This document is intended
|
||||
for emulator developers and Genesis programmers.
|
||||
Feel free to pass this document around freely. If you use any parts of
|
||||
it that were contributed by people other than me, it would be a good idea to
|
||||
give them credit.
|
||||
Any useful feedback is very much appreciated, especially corrections
|
||||
and new entries. Do not ask about ROMs or anything stupid. trzy@powernet.net
|
||||
Check my page at: http://www.powernet.net/~trzy as well.
|
||||
Much thanks to Joe Groff, Steve Snake, nyef, ATani, and Flavio for
|
||||
the invaluable help.
|
||||
|
||||
|
||||
-- Table of Contents --
|
||||
0. Control Port Write Modes
|
||||
1. Auto-Increment
|
||||
2. VRAM Address Decoding (for Writing)
|
||||
3. Tiles
|
||||
4. Scroll Layer Name Tables
|
||||
5. Scroll Layers and Video Resolution
|
||||
6. Joypads
|
||||
7. Crash Course on the Genesis Security System and Common Don'ts
|
||||
8. Emulating RAM and ROM w/ Starscream
|
||||
9. SMD ROM Format
|
||||
|
||||
|
||||
-- 0. Control Port Write Modes --
|
||||
|
||||
The VDP control port, 0xC00004, has two write modes: "Register Set" (write1)
|
||||
and "Address Set" (write2). The VDP is able to distinguish between which mode
|
||||
you want to use by looking at bits 15 and 14 of the word you write to the
|
||||
control port.
|
||||
|
||||
10: Write1 Otherwise: Write2
|
||||
|
||||
For write2, bits 15 and 14 are CD1 and CD0 so the concern of conflict arises.
|
||||
If you look at the possible access modes which are specified by the 6 CD bits
|
||||
you will not find any that have 10 in CD1 and CD0.
|
||||
|
||||
|
||||
-- 1. Auto-Increment --
|
||||
|
||||
The auto-increment value (in register #15) is apparently set to 2 by default.
|
||||
|
||||
|
||||
-- 2. VRAM Address Decoding (for Writing) --
|
||||
|
||||
For words and longwords, the VRAM address decoding process is not as
|
||||
straightforward as some would have you believe. The A0 address bit is not used
|
||||
in decoding, what this apparently means is that it is treated as 0 (thus
|
||||
preventing misaligned word writes).
|
||||
A0 is used to test wether or not the bytes in a word should be swapped
|
||||
or not. If A0 = 1, they are swapped, if it is 0, then bytes are not swapped.
|
||||
A0 is also used when adding the auto-increment value to the VRAM address after
|
||||
some data is written.
|
||||
|
||||
C example of emulating this:
|
||||
|
||||
if (addr & 1)
|
||||
data = ByteSwap(data);
|
||||
*((unsigned short int *) (vram + (addr & 0xfffe))) = data;
|
||||
addr += auto_inc;
|
||||
|
||||
|
||||
-- 3. Tiles --
|
||||
|
||||
The Genesis tile format is quite simple. Each pixel is represented by 4 bits
|
||||
thus allowing 16 colors per every tile. Tiles are 8x8. The Genesis allows for
|
||||
up to 64 colors to be displayed: 16 per palette, with 4 palettes. Palettes are
|
||||
not specified in the tile bitmap, that information is elsewhere and beyond the
|
||||
scope of this note.
|
||||
|
||||
Example of a bitmap for the letter "A". We use the color 0xa for each
|
||||
of the pixels. Remember, color 0 is _always_ transparent in any
|
||||
palette:
|
||||
|
||||
dc.l $00077000
|
||||
dc.l $07700770
|
||||
dc.l $07700770
|
||||
dc.l $07777770
|
||||
dc.l $07700770
|
||||
dc.l $07700770
|
||||
dc.l $00000000
|
||||
dc.l $00000000
|
||||
|
||||
|
||||
-- 4. Scroll Layer Name Tables --
|
||||
|
||||
Scroll layers (who's addresses and sizes are specified in VDP registers) are
|
||||
"name tables" where each entry contains an index to a specific 8x8 tile. These
|
||||
entries are arranged in a linear fashion.
|
||||
Each entry is a word in size. Here is the format for an entry:
|
||||
|
||||
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
|PRI|PL1|PL0|VFP|HFP|I10|I9 |I8 |I7 |I6 |I5 |I4 |I3 |I2 |I1 |I0 |
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
PRI Priority (1 = highest, on top; 0 = lowest, on bottom)
|
||||
PL1-PL0 Palette (0, 1, 2, or 3)
|
||||
VFP Vertical flipping (1 = true)
|
||||
HFP Horizontal flipping (1 = true)
|
||||
I10-I0 Index of 8x8 tile in pattern area (VRAM $0000).
|
||||
Multiply this by 32 to get offset in VRAM of the tile
|
||||
bitmap
|
||||
|
||||
The information here applies to both Scroll A and Scroll B, please refer to
|
||||
more complete documentation for information on how to set Scroll layer
|
||||
addresses and what-not.
|
||||
|
||||
|
||||
-- 5. Scroll Layers and Video Resolution --
|
||||
|
||||
The Genesis supports two video modes: 32x28 cell and 40x28 cell (which in
|
||||
pixels are 256x224 and 320x224.) The video resolution is how many 8x8 tiles
|
||||
are displayed on-screen. The vertical portion differs with PAL I believe, but
|
||||
it that is not relevant.
|
||||
Scroll A and Scroll B can have a number of different sizes which
|
||||
obviously often cannot be all shown on-screen: 32x32, 32x64, 32x128, 64x32,
|
||||
64x64, and 128x32. The Sega Programming FAQ says that 128x128 is possible, but
|
||||
I don't think it is since that would take up 32KB of VRAM which would not
|
||||
leave room for the other Scroll layer, the Window, or the patterns.
|
||||
|
||||
Only a portion of the Scroll layer is visible on the screen. How it is
|
||||
displayed can be represented by the following diagram:
|
||||
|
||||
** Assuming the Scroll size is 64x64 and the screen 40x28, everything is
|
||||
addressed in cell units (obviously not to scale) **
|
||||
|
||||
- = Scroll layer
|
||||
* = Visible portion
|
||||
|
||||
H0 H39 H63
|
||||
+****************************************--------------------+
|
||||
V0 |* V0 * |
|
||||
|* * |
|
||||
|* * |
|
||||
|* * |
|
||||
|* * |
|
||||
|* V27 * |
|
||||
|**************************************** |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
V63 | |
|
||||
+------------------------------------------------------------+
|
||||
|
||||
Thus you can see that there are tiles beyond the right limit of the visible
|
||||
screen, and below as well. This method of having the layer larger than can be
|
||||
displayed is for scrolling. The above is what would occur if one set the
|
||||
Scroll size to 64x64 and the resolution to 40x28 without scrolling the screen
|
||||
or anything.
|
||||
If you are having problems emulating Scroll layers because everything
|
||||
is shifted over you are probably forgetting to render the invisible parts of
|
||||
the Scroll or to skip over them and on to the next visible row. I hope that
|
||||
made sense.
|
||||
|
||||
|
||||
-- 6. Joypads --
|
||||
|
||||
** Begin Email **
|
||||
From: Joe Groff
|
||||
To: Bart Trzynadlowski
|
||||
Date: Sat, 15 Jan 2000 23:06:49 -0800 (PST)
|
||||
Subject: Re: DGen/SDL
|
||||
|
||||
> is there any good info anywhere on control pad interfacing?
|
||||
|
||||
As far as I can tell, this is how the controller works. There are two one-byte
|
||||
data sets:
|
||||
v & 0x40: always set
|
||||
v & 0x20: C
|
||||
v & 0x10: B
|
||||
v & 0x08: right
|
||||
v & 0x04: left
|
||||
v & 0x02: down
|
||||
v & 0x01: up
|
||||
and:
|
||||
v & 0x40: always clear
|
||||
v & 0x20: START
|
||||
v & 0x10: A
|
||||
v & 0x08: right
|
||||
v & 0x04: left
|
||||
v & 0x02: down
|
||||
v & 0x01: up
|
||||
By reading a word from 0xA10002 (for first controller) or 0xA10004 (for
|
||||
second), the word will have one of the above bitmasks written to both bytes.
|
||||
If you write a byte to 0xA10003(for 1st) or 0xA10005(for 2nd) with the 0x40
|
||||
bit set, you'll get the first set, otherwise you'll get the second.
|
||||
|
||||
Example:
|
||||
Player 1 is pressing left and the A and B buttons simultaneously. Player 2
|
||||
is pressing B, C, and START. As the game, in order to probe controller 1:
|
||||
- I send byte 0x00 to 0xA10003 (or word 0x0000 to 0xA10002 :)
|
||||
- I read a word from 0xA10002, which gives me 0x1414. From the lower table,
|
||||
I see A and left are being pressed.
|
||||
- I send byte 0x40 to 0xA10003.
|
||||
- I read another word from 0xA10002. This time I get 0x5454, which from the
|
||||
upper table means B and left are being pressed.
|
||||
Similarly, to probe controller 2:
|
||||
- I send byte 0x00 to 0xA10005.
|
||||
- I read from 0xA10004, and get 0x2020. So START is being depressed.
|
||||
of the controller!
|
||||
- I send byte 0x40 to 0xA10005.
|
||||
- I read from 0xA10004 again, get 0x7070, so B and C are being pressed.
|
||||
|
||||
There's also a lot of odd code to handle 6-button controllers in DGen, but
|
||||
as it's getting a bit late, I can't quite understand it. Hopefully this is
|
||||
accurate and clear enough to at least get you started.
|
||||
** End Email **
|
||||
|
||||
** Begin Email **
|
||||
From: ATani
|
||||
To: Bart Trzynadlowski
|
||||
Date: Sat, 15 Jan 2000 23:06:43 -0800
|
||||
Subject: Re: genesis tech question post
|
||||
|
||||
Ok, Well on the genesis the joysticks are read in by the z80 and passed to
|
||||
the 68000 chip via memory addresses: A10003 & A10005.
|
||||
|
||||
If bit 6 of the Stored Controller 1 information is set then you return the
|
||||
following information when reading Address: A10003 (Byte mode):
|
||||
|
||||
Bit: Description:
|
||||
0 Up
|
||||
1 Down
|
||||
2 Left
|
||||
3 Right
|
||||
4 B
|
||||
5 C
|
||||
|
||||
If Bit 6 is not set return the following:
|
||||
Bit: Description:
|
||||
4 A
|
||||
5 Start
|
||||
|
||||
Address A10005 is the same except values returned are for joystick port 2.
|
||||
|
||||
The Stored data are in reference to the byte values written to A10003 and
|
||||
A10005 (joystick port 1 and joystick port 2)
|
||||
** End Email **
|
||||
|
||||
Flavio points out the information from ATani's email may be somewhat faulty:
|
||||
|
||||
"The Z80 has nothing to do with joypad reading. Actually, I believe the Z80
|
||||
banker thingy will go wacko, should you attempt such a stunt. Gotta test
|
||||
that."
|
||||
|
||||
|
||||
-- 7. Crash Course on the Genesis Security System and Common Don'ts --
|
||||
|
||||
** The following information is courtesy of Flavio **
|
||||
|
||||
Crash course in Genesis security:
|
||||
|
||||
1) There must be either 'SEGA' or ' SEGA' in ASCII at offset 0x100 (256
|
||||
decimal.)
|
||||
|
||||
2) If the four least significant bits of 0xA10001 are higher than zero, the
|
||||
poor programmer must write 'SEGA' to 0xA14000.
|
||||
Example:
|
||||
MOVE.B $A10001, D0
|
||||
ANDI.B #$F, D0
|
||||
BEQ.S NO_VDP_LOCK
|
||||
MOVE.L #'SEGA', $A14000.
|
||||
NO_VDP_LOCK:
|
||||
[Yer code here]
|
||||
|
||||
Yes, I know many of you can't read 68K ASM yet, but I don't know how to do
|
||||
this on Paul Lee's C compiler (or any other for that matter.) :/
|
||||
|
||||
A list of common Caveat Gennyptor's follows:
|
||||
|
||||
- Be careful not to access forbidden addresses (see SEGA2.DOC), as the Genny
|
||||
locks up instantly if you dare to touch them.
|
||||
- Don't read from the VDP data port (C00000) if you have sent a
|
||||
"VRAM/CRAM/VSRAM write" command (and vice versa.)
|
||||
- The FM doesn't work if the Z80 is reset (their reset lines are wired
|
||||
together.)
|
||||
- Always have the Z80 busreq'ed before reading the joyports.
|
||||
- Never attempt to read PSG ports.
|
||||
- DMA transfers should be controlled by code placed at the Genny's work RAM
|
||||
(0xFF0000-0xFFFFFF.)
|
||||
- Don't attempt to transfer data to/from the VDP if a DMA is in progress.
|
||||
- Z80 RAM _must_ be accessed in byte units.
|
||||
- Don't toggle the joystick's select line more than four times per vertical
|
||||
refresh, to ensure 6-button joypad compatibility.
|
||||
- It takes at least 16 68K clock ticks for the joyport readouts to become
|
||||
really stable, after you have toggled the aforementioned select line.
|
||||
|
||||
Flavio has also pointed out one more important thing not to attempt:
|
||||
|
||||
CLR, ST, and TAS cannot be used to access the C000xx range. (It's a
|
||||
derivative of the "don't read with the VDP set to write" commandment.)
|
||||
|
||||
|
||||
-- 8. Emulating RAM and ROM w/ Starscream --
|
||||
|
||||
Often times, Genesis games do some odd tricks that can be buggers to emulate.
|
||||
One of these is jumping backwards (which causes the 24-bit address to wrap
|
||||
around to 0xFFFFFF) into work RAM to execute code. Since Starscream uses
|
||||
32-bit data to handle addresses, this sort of maneuver would wrap around to
|
||||
0xFFFFFFFF (32-bit) which is out of the Genesis address space.
|
||||
Below is part of a Starscream context for emulating the Genesis work
|
||||
RAM and ROM. I have also included the code for the handlers (Joe Groff helped
|
||||
with this -- thanks Joe!) The dummy handlers are for regions of the address
|
||||
space where accesses are ignored (I have removed all references to VDP and I/O
|
||||
stuff since it would just clutter the example.) In reality, the data items
|
||||
rom and ram would be dynamically allocated and would have to be added to these
|
||||
structures during initialization time. They would be seen here as (unsigned)
|
||||
NULL or (void *) NULL.
|
||||
|
||||
struct STARSCREAM_PROGRAMREGION fetch_instructions[] =
|
||||
{
|
||||
{ 0x000000, 0x3fffff, (unsigned) rom },
|
||||
{ 0xff0000, 0xffffff, (unsigned) ram - 0xff0000 },
|
||||
{ 0xff000000, 0xff3fffff, (unsigned) ram - 0xff000000 },
|
||||
{ 0xfff00000, 0xffffffff, (unsigned) ram - 0xfff00000 },
|
||||
{ -1, -1, NULL }
|
||||
};
|
||||
struct STARSCREAM_DATAREGION read_data_byte[] =
|
||||
{
|
||||
{ 0x000000, 0x3fffff, NULL, (void *) rom },
|
||||
{ 0x400000, 0xffffff, StarscreamReadRAMByte, NULL },
|
||||
{ -1, -1, NULL, NULL }
|
||||
};
|
||||
struct STARSCREAM_DATAREGION read_data_word[] =
|
||||
{
|
||||
{ 0x000000, 0x3fffff, NULL, (void *) rom },
|
||||
{ 0x400000, 0xdfffff, StarscreamFakeRead, NULL },
|
||||
{ 0xe00000, 0xffffff, StarscreamReadRAMWord, NULL },
|
||||
{ -1, -1, NULL, NULL }
|
||||
};
|
||||
struct STARSCREAM_DATAREGION write_data_byte[] =
|
||||
{
|
||||
{ 0x000000, 0xdfffff, StarscreamFakeWrite, NULL },
|
||||
{ 0xe00000, 0xffffff, StarscreamWriteRAMByte, NULL },
|
||||
{ -1, -1, NULL, NULL }
|
||||
};
|
||||
struct STARSCREAM_DATAREGION write_data_word[] =
|
||||
{
|
||||
{ 0x000000, 0xdfffff, StarscreamFakeWrite, NULL },
|
||||
{ 0xe00000, 0xffffff, StarscreamWriteRAMWord, NULL },
|
||||
{ -1, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
unsigned StarscreamReadRAMByte(unsigned address)
|
||||
{
|
||||
return ram[(address ^ 1) & 0xffff];
|
||||
}
|
||||
|
||||
unsigned StarscreamReadRAMWord(unsigned address)
|
||||
{
|
||||
return *((unsigned short *) (ram + (address & 0xfffe)));
|
||||
}
|
||||
|
||||
void StarscreamWriteRAMByte(unsigned address, unsigned data)
|
||||
{
|
||||
ram[(address ^ 1) & 0xffff] = data;
|
||||
}
|
||||
|
||||
void StarscreamWriteRAMWord(unsigned address, unsigned data)
|
||||
{
|
||||
*((unsigned short *) (ram + (address & 0xfffe))) = data;
|
||||
}
|
||||
|
||||
unsigned StarscreamFakeRead(unsigned address)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StarscreamFakeWrite(unsigned address, unsigned data)
|
||||
{
|
||||
}
|
||||
|
||||
RAM is at 0xff0000-0xffffff and is mirrored every 64KB at 0xe00000-0xfeffff.
|
||||
|
||||
Please see the Starscream documentation for information on how the core works.
|
||||
At the time of this writing, Neill Corlett's page is at:
|
||||
http://www4.ncsu.edu/~nscorlet/
|
||||
|
||||
|
||||
-- 9. SMD ROM Format --
|
||||
|
||||
The SMD ROM format consists of a 512 byte header and the actual ROM image in
|
||||
16KB chunks with the odd bytes at the beginning, and the even bytes at the
|
||||
end.
|
||||
|
||||
Header offsets:
|
||||
0x00: Number of 16KB blocks. This number is often incorrect and it
|
||||
is wise to calculate it manually: (sizeof(file) - 512) / 16384
|
||||
0x02: If 0, the ROM is standalone or the last part of a series.
|
||||
Otherwise it is part of a split ROM set.
|
||||
0x08: 0xaa
|
||||
0x09: 0xbb
|
||||
|
||||
Note: Most ROMs have 0xaa and 0xbb at 0x08 and 0x09 but a very small percentage
|
||||
(about 1.28% by my calculations) do not conform to this. Those offsets are
|
||||
useful for checking wether a ROM is in SMD format but be aware that they are
|
||||
not always correct.
|
||||
|
||||
Decoding a 16KB SMD blocke: (thanks to XnaK and Kuwanger)
|
||||
1. If the byte offset in the block is less than 8192, copy the byte
|
||||
from the SMD block to the first unused odd offset in the decode
|
||||
buffer.
|
||||
2. Otherwise, put it in the first unused even offset in the decode
|
||||
buffer.
|
||||
|
||||
Example block-decoding C function: (from my own GROM v0.75)
|
||||
|
||||
void smd_bin(unsigned char *bin_block, unsigned char *smd_block)
|
||||
{
|
||||
int i, o = 1, e = 0;
|
||||
|
||||
/* convert 16KB of SMD to BIN */
|
||||
for (i = 0; i < 8192; i++)
|
||||
{
|
||||
bin_block[o] = smd_block[i];
|
||||
bin_block[e] = smd_block[i + 8192];
|
||||
o += 2;
|
||||
e += 2;
|
||||
}
|
||||
}
|
||||
|
||||
Get GROM at:
|
||||
http://www.powernet.net/~trzy
|
||||
http://www.zophar.net
|
||||
http://eidolon.psp.net
|
||||
http://www.vintagegaming.com
|
||||
...or...
|
||||
If all else fails, email me.
|
||||
|
||||
|
BIN
docs/genplus.doc
Normal file
BIN
docs/genplus.doc
Normal file
Binary file not shown.
312
docs/gensave.txt
Normal file
312
docs/gensave.txt
Normal file
@ -0,0 +1,312 @@
|
||||
----------------------------------------------
|
||||
SEGA GENESIS EMULATOR SAVE STATE REFERENCE
|
||||
Third Edition (February 23, 2002)
|
||||
Bart Trzynadlowski
|
||||
----------------------------------------------
|
||||
|
||||
|
||||
---------
|
||||
About
|
||||
---------
|
||||
|
||||
The aim of this reference is to document the save state and backup RAM formats
|
||||
of the various Sega Genesis emulators out there. Distribute this document
|
||||
freely, but please keep it unmodified. If you use any of this information,
|
||||
give credit to the contributors and me.
|
||||
|
||||
The following people contributed directly and/or indirectly:
|
||||
|
||||
- Charles MacDonald (supplied most of the Genecyst save state information)
|
||||
- Jeffrey Quinn (found the SSP and USP in Genecyst states)
|
||||
- Steve Snake (contributed Genecyst and KGen98 information)
|
||||
- Langoustator (supplied YM2612 register information and some KGen98 data)
|
||||
|
||||
More information on any of the formats, especially the KGen format, would be
|
||||
appreciated. You can reach me at bart@dynarec.com or visit my web site at
|
||||
http://www.dynarec.com/~bart.
|
||||
|
||||
A "byte" is considered to be 8 bits, a "word" is 16 bits, and a "double word"
|
||||
is 32 bits.
|
||||
|
||||
Change History
|
||||
--------------
|
||||
|
||||
February 12, 2002: Second Edition
|
||||
- Added some Genecyst and KGen save state information
|
||||
supplied by Steve Snake
|
||||
- Corrected some typos
|
||||
|
||||
April 11, 2001: First Edition
|
||||
- Initial public release
|
||||
|
||||
|
||||
------------------------------
|
||||
Genecyst Save State Format
|
||||
------------------------------
|
||||
|
||||
The Genecyst save state format (GST) is used by various emulators. The files
|
||||
use the extensions GS0-GS9 depending on the save slot. The information in this
|
||||
section has been validated against Genecyst v0.32b. I believe Version X.XX is
|
||||
very similar, if not the same, but I would appreciate confirmation.
|
||||
|
||||
Offset Range: Description:
|
||||
------------- ------------
|
||||
0x00000-0x00002 Signature: "GST"
|
||||
0x00006 0xE0, apparently used to validate file integrity
|
||||
0x00007 0x40, apparently used to validate file integrity
|
||||
0x00080-0x0009F 68K registers D0-D7
|
||||
0x000A0-0x000BF 68K registers A0-A7
|
||||
0x000C8-0x000CB 68K PC
|
||||
0x000D0-0x000D1 68K SR
|
||||
0x000D2-0x000D5 68K USP
|
||||
0x000D6-0x000D9 68K SSP
|
||||
0x000FA-0x00112 VDP registers (0-23, 1 byte each)
|
||||
0x00112-0x00191 CRAM
|
||||
0x00192-0x001E1 VSRAM
|
||||
0x001E4-0x003E3 YM2612 registers
|
||||
0x00404-0x00437 Z80 registers: AF, BC, DE, HL, IX, IY, PC, SP, AF',
|
||||
BC', DE', HL', I (stored as a double word each.) R is
|
||||
not supported and IM is presumed to be 1
|
||||
0x00438 Z80 IFF1 (IFF2 is assumed to be the same)
|
||||
0x00439 Z80 status (0 = stopped, 1 = running), probably has
|
||||
something to do with BUSREQ
|
||||
0x0043C-0x0043F Z80 window bank
|
||||
0x00474-0x002473 Z80 RAM
|
||||
0x02478-0x12477 68K RAM
|
||||
0x12478-0x22477 VRAM
|
||||
|
||||
Steve Snake sent me word that 0x00434 (byte) is the Z80 I register and
|
||||
0x00437 (byte) is the Z80 interrupt mode. This conflicts with my data
|
||||
which says 0x00434 is a double word where I is stored. I'm not sure which
|
||||
is correct.
|
||||
|
||||
All data is in little endian format except for 68K RAM, VSRAM, and VRAM, which
|
||||
are in big endian format. Areas not mentioned should be kept 0.
|
||||
|
||||
Locations 0x00006 and 0x00007 are not completely understood. Genecyst expects
|
||||
them to be 0xE0 and 0x40, respectively. This has been observed in Genecyst
|
||||
v0.20, v0.32b, and vX.XX. Many emulators avoid saving these bytes and Genecyst
|
||||
refuses to load their states.
|
||||
|
||||
The USP and SSP are tricky. If the supervisor bit in SR is set, only the USP
|
||||
is saved at 0x000D2, the SSP at 0x000D6 is set to 0. If the supervisor bit is
|
||||
cleared, both the USP at 0x000D2 and the SSP at 0x000D6 are saved. A7 is also
|
||||
the current stack pointer (SSP if supervisor mode, USP if user mode.)
|
||||
|
||||
Information on the YM2612 registers was sent to me by Langoustator who says it
|
||||
is valid for Gens save states and is assumed to be valid for true Genecyst
|
||||
states as well. None of it has been verified by me, but I'll assume it is
|
||||
correct:
|
||||
|
||||
- 0x001E4-0x00205: Apparently unused
|
||||
- 0x00206-0x00213: General registers (not channel specific.) There are
|
||||
only 9 registers at: 0x206, 0x208, 0x209, 0x20A,
|
||||
0x20B, 0x20C, 0x20E, and 0x20F.
|
||||
- 0x00214-0x002E3: Channel-specific registers for channels 1-3. They are
|
||||
stored in 4 byte groups with each group layed out like
|
||||
this:
|
||||
|
||||
First byte = Channel 1
|
||||
Second byte = Channel 2
|
||||
Third byte = Channel 3
|
||||
Fourth byte = Unused (0)
|
||||
|
||||
The registers only appear to end at 0x0029B and the
|
||||
rest of the area (from 0x0029C-0x002E3) is unused.
|
||||
|
||||
- 0x002E4-0x00313: Apparently unused
|
||||
- 0x00314-0x003E3: Channel-specific registers for channels 4-6. They are
|
||||
stored in 4 byte groups like the channel 1-3 registers.
|
||||
They end at 0x0039B and the rest of the area (from
|
||||
0x0039C-0x003E3) is unused.
|
||||
|
||||
More information is needed, especially on (but not limited to) the following:
|
||||
|
||||
- PSG state
|
||||
- Internal VDP information (control port status, VDP RAM pointer, etc.)
|
||||
|
||||
|
||||
------------------------------
|
||||
Genecyst Backup RAM Format
|
||||
------------------------------
|
||||
|
||||
Genecyst saves backup RAM in files with the GSV extension. They simply contain
|
||||
the backup RAM in little endian format. The files do not always have an even
|
||||
number of bytes.
|
||||
|
||||
Even if backup RAM only appears in the odd or even addresses, Genital saves
|
||||
the unused bytes (which should be 0.)
|
||||
|
||||
Those emulators which keep the 68K address space in little endian format can
|
||||
support GSV files easily: simply copy the contents of the files unmodified to
|
||||
the backup RAM area.
|
||||
|
||||
A few emulators, including Genital, use the GSV format.
|
||||
|
||||
|
||||
----------
|
||||
KGen98
|
||||
----------
|
||||
|
||||
There is no official information on KGen's save state format, so I decided to
|
||||
take it upon myself to try reverse engineering the format. Due to a lack of
|
||||
time, I have not been able to learn more than is shown here. It might be
|
||||
enough to load states, but isn't enough to save them.
|
||||
|
||||
The below information applies to KGen98 v0.4b, I do not know if it applies to
|
||||
other versions of KGen and KGen98. Any more information is most welcome.
|
||||
|
||||
Offset Range: Description:
|
||||
------------- ------------
|
||||
0x00000-0x00002 Signature: "KSS"
|
||||
0x00003 Must be 0x1, also part of the signature
|
||||
0x00004-0x00005 ROM checksum, word sized
|
||||
0x00008-0x00096 Path to ROM (zero terminated), when path is at maximum
|
||||
length, 0x96 contains the last character of the path
|
||||
0x00097 Always 0
|
||||
0x00098-0x02097 Z80 RAM
|
||||
0x02098-0x12097 68K RAM
|
||||
0x12098-0x22097 VRAM
|
||||
0x22098-0x22117 CRAM
|
||||
0x22298-0x222E7 VSRAM
|
||||
0x2235C-0x2237B 68K registers D0-D7
|
||||
0x2237C-0x2239B 68K registers A0-A7
|
||||
0x2239C-0x2239F 68K SP (if supervisor mode: USP, if user mode: SSP)
|
||||
0x223A0-0x223A3 68K PC
|
||||
0x223A4-0x223A7 68K SR
|
||||
0x223A8-0x223AB Previous SR value (Steve says only the high byte is
|
||||
necessary), used to detect changes between privilege
|
||||
levels
|
||||
0x223AE-0x223C5 VDP registers (0-23, 1 byte each)
|
||||
0x2273E-0x227?? Data written to VDP control port
|
||||
0x22742-0x22743 Control port half: if only one word of a 2-word
|
||||
command was written, it is stored here
|
||||
0x22748-0x22749 Current VDP RAM address
|
||||
|
||||
The checksum, 68K RAM, VRAM, CRAM, and VSRAM are stored in big endian format.
|
||||
Everything else is in little endian format.
|
||||
|
||||
I believe location 0x2273E is a little endian double word. There is plenty of
|
||||
important internal VDP and FM data kept at the end of the file. I haven't
|
||||
found the meaning of all of it. Also, the path to the save state's ROM file is
|
||||
saved near the beginning of the file.
|
||||
|
||||
|
||||
-----------------
|
||||
Genital v1.2+
|
||||
-----------------
|
||||
|
||||
Starting with Version 1.2, Genital save state files use a version numbering
|
||||
system independent from Genital itself. Save states with different major
|
||||
version numbers are not compatible. The minor version number indicates changes
|
||||
in the format which do not affect backwards compatibility.
|
||||
|
||||
Version 1.0 of this new GNS format is described below:
|
||||
|
||||
Offset Range: Description:
|
||||
------------- ------------
|
||||
0x00000-0x00002 Signature: "GNS"
|
||||
0x00003 Format major version
|
||||
0x00004 Format minor version
|
||||
0x00005-0x00007 Reserved (always keep 0)
|
||||
0x00008-0x00057 68K registers and status (from Genital68K context)
|
||||
0x00058-0x00077 68K pending interrupts (from Genital68K context)
|
||||
0x00078-0x10077 68K RAM
|
||||
0x10078-0x20077 VRAM
|
||||
0x20078-0x200F7 CRAM
|
||||
0x200F8-0x20147 VSRAM
|
||||
0x20148-0x201A7 VDP registers (0-23; double word each)
|
||||
0x201A8-0x201BF VDP internal status data (taken directly from VDP
|
||||
context: ctrlport_mode, access_mode, addr, addr_top,
|
||||
dma_mode, and status_register; double word each)
|
||||
0x201C0-0x201C3 VDP horizontal interrupt timer
|
||||
0x201C4-0x201C7 Reserved (always keep 0)
|
||||
0x201C8-0x201CB Z80 BUSREQ
|
||||
0x201CC-0x201EB Z80 registers (word each: AF, BC, DE, HL, IX, IY, PC, SP,
|
||||
AF', BC', DE', HL', IR, IM, IFF1, IFF2)
|
||||
0x201EC-0x221EB Z80 RAM
|
||||
|
||||
Everything is stored in little endian format.
|
||||
|
||||
The 68K registers and status come directly from the Genital68K context, occupy
|
||||
a double word each, and are ordered:
|
||||
|
||||
D0-D7, A0-A7, SP, SR, PC, status
|
||||
|
||||
The "SP" relies on the privilege mode. If in supervisor mode, this is the USP
|
||||
(and the SSP is in A7.) If in user mode, this is the SSP (and the USP is in
|
||||
A7.) Please read the Genital68K (now Turbo68K) documentation for information
|
||||
on what the "status" is (http://www.dynarec.com/~bart/turbo68k.)
|
||||
|
||||
The first 7 elements pending interrupt array correspond to interrupt levels
|
||||
1-7. Each element, a double word in size, contains the vector of the interrupt
|
||||
that is pending. The eighth element is the number of interrupts pending.
|
||||
Again, see the Genital68K documentation for more information.
|
||||
|
||||
The VDP internal status comes directly from Genital's VDP context. The
|
||||
"ctrlport_mode" indicates which part of a command the control port expects. If
|
||||
0, it expects the first part, otherwise the second. The access_mode is just
|
||||
the VDP's CD bits which indicate VRAM write, CRAM write, VSRAM write, VRAM
|
||||
read, etc. The VDP RAM current address is stored in the "addr" element. Bits
|
||||
15 and 14 of the VDP RAM address are stored in bits 1 and 0 of "addr_top."
|
||||
These are used to emulate a peculiar feature of the VDP. The "dma_mode" stores
|
||||
the DMA mode bits. The "status_register" is the VDP Status Register.
|
||||
|
||||
The "horizontal interrupt timer" is the count-down timer which triggers
|
||||
horizontal interrupts.
|
||||
|
||||
|
||||
---------------------------
|
||||
Genital (v1.0 and v1.1)
|
||||
---------------------------
|
||||
|
||||
The Genital save state format (GNS) was introduced in Genital v1.0 and was
|
||||
completely changed by v1.2. Versions 1.0 and 1.1 used the format described
|
||||
below.
|
||||
|
||||
Offset Range: Description:
|
||||
------------- ------------
|
||||
0x00000-0x0FFFF 68K RAM
|
||||
0x10000-0x1FFFF VDP VRAM
|
||||
0x20000-0x21FFF Z80 RAM
|
||||
0x22000-0x2207F VDP CRAM
|
||||
0x22080-0x220CF VDP VSRAM
|
||||
0x220D0-0x220EF 68K registers A0-A7
|
||||
0x220F0-0x220F3 68K SP (if supervisor mode: USP, if user: SSP)
|
||||
0x220F4-0x22113 68K registers D0-D7
|
||||
0x22114-0x22117 68K SR
|
||||
0x22118-0x2211B 68K PC
|
||||
0x2211C-0x2214F Z80 registers: AF, BC, DE, HL, IX, IY, PC, SP, AF',
|
||||
BC', DE', HL', IR (stored as a double word each)
|
||||
0x22150-0x22153 Z80 BUSREQ
|
||||
0x22154-0x221B3 VDP registers (0-23, double word each)
|
||||
0x221B4-0x221B7 VDP control port mode
|
||||
0x221B8-0x221BB VDP RAM address pointer
|
||||
0x221BC-0x221BF VDP RAM access mode
|
||||
0x221C0-0x221C3 VDP DMA mode
|
||||
0x221C4-0x221C7 VDP Status Register
|
||||
0x221C8-0x221CB VDP HV counter
|
||||
0x221CC-0x221CF VDP Horizontal Interrupt timer
|
||||
0x221D0-0x221D3 VDP Control Port A15, A14
|
||||
0x221D4-0x221DA Reserved (7 bytes; should be 0)
|
||||
0x221DB Major version number of Genital
|
||||
0x221DC Minor version number of Genital
|
||||
0x221DD-0x221DF Signature: "GNS"
|
||||
|
||||
The 68K RAM, VRAM, CRAM, and VSRAM are stored in big endian format. Everything
|
||||
else is in little endian format.
|
||||
|
||||
The VDP RAM address pointer is the current VRAM, CRAM, or VSRAM address. The
|
||||
VDP RAM access mode is just the CD bits in a VDP command which indicate
|
||||
whether the VDP is in VRAM write mode, VRAM read mode, CRAM write mode, etc.
|
||||
|
||||
The VDP Control Port mode indicates which part of the command the VDP is
|
||||
expecting. This is the "pending flag" described by Charles MacDonald's VDP
|
||||
document. The A15, A14 bits are those last written to the control port. When
|
||||
the first word of an address set command is written, these bits are used to
|
||||
fill in A15, A14. They are stored in bits 1 and 0 of the GNS double word.
|
||||
|
||||
The major and minor version numbers reflect the version of Genital which
|
||||
produced the save state. For example, if the state was created with Genital
|
||||
v1.0, the major version would be 1 and the minor would be 0. The signature
|
||||
must be "GNS" in ASCII or the save state will be deemed corrupt.
|
1654
docs/genvdp.txt
Normal file
1654
docs/genvdp.txt
Normal file
File diff suppressed because it is too large
Load Diff
933
docs/io.htm
Normal file
933
docs/io.htm
Normal file
@ -0,0 +1,933 @@
|
||||
<html><head><title>Sega Genesis I/O Chip and Peripherals</title></head><body>
|
||||
|
||||
<h2>Sega Genesis I/O Chip and Peripherals</h2>
|
||||
By Charles MacDonald<br>
|
||||
<a href="http://cgfm2.emuviews.com/">http://cgfm2.emuviews.com</a>
|
||||
<hr>
|
||||
|
||||
<h4>Contents</h4>
|
||||
<ul>
|
||||
<li><a href="#ovr">Overview</a>
|
||||
</li><li><a href="#con">Connector details</a>
|
||||
</li><li><a href="#cpu">CPU interface</a>
|
||||
</li><li><a href="#reg">Register list</a>
|
||||
</li><li><a href="#ver">Version register</a>
|
||||
</li><li><a href="#dat">Data register</a>
|
||||
</li><li><a href="#dir">Control register</a>
|
||||
</li><li><a href="#scr">Serial control register</a>
|
||||
</li><li><a href="#txd">TxData register</a>
|
||||
</li><li><a href="#rxd">RxData register</a>
|
||||
</li><li><a href="#ser">Using serial communication</a>
|
||||
</li><li><a href="#per">Peripheral devices</a>
|
||||
<ul>
|
||||
<li><a href="#md2">2-button Mark-III gamepad</a>
|
||||
</li><li><a href="#md3">3-button standard gamepad</a>
|
||||
</li><li><a href="#md6">Fighting Pad 6B</a><i>(incomplete)</i>
|
||||
</li><li><a href="#gun">Lightguns (Sega Menacer, Konami Justifier)</a><i>(incomplete)</i>
|
||||
</li><li><a href="#eat">EA 4-Way Play</a>
|
||||
</li><li><a href="#mul">Sega Team Player</a><i>(incomplete)</i>
|
||||
</li><li><a href="#mmo">Sega Mega Mouse</a>
|
||||
</li></ul>
|
||||
</li><li><a href="#msc">Miscellaneous</a>
|
||||
</li><li><a href="#dis">Disclaimer</a>
|
||||
</li></ul>
|
||||
|
||||
<a name="ovr">
|
||||
</a><h4><a name="ovr">Overview</a></h4>
|
||||
<p>
|
||||
<a name="ovr"> The I/O chip manages three 7-bit I/O ports. It also
|
||||
provides an way for the CPU to read the state of several jumpers in the
|
||||
system. Later versions of the Genesis hardware have the I/O chip
|
||||
integrated into some of the other custom hardware, but they all
|
||||
function identically.
|
||||
</a></p>
|
||||
|
||||
<a name="con">
|
||||
</a><h4><a name="con">Connector details</a></h4>
|
||||
<p>
|
||||
<a name="con"> Ports A and B are male DB-9 connectors, while port C is
|
||||
female. In the Genesis 2 and 3, there is no physical connector for port
|
||||
C, but it can still be programmed and will respond like any other port.
|
||||
(as if no gamepad was connected) Here are the pin assignments:
|
||||
</a></p>
|
||||
|
||||
<pre><a name="con"> Pin 1 : D0
|
||||
Pin 2 : D1
|
||||
Pin 3 : D2
|
||||
Pin 4 : D3
|
||||
Pin 5 : +5V
|
||||
Pin 6 : TL
|
||||
Pin 7 : TH
|
||||
Pin 8 : Ground
|
||||
Pin 9 : TR
|
||||
</a></pre>
|
||||
|
||||
<a name="cpu">
|
||||
</a><h4><a name="cpu">CPU interface</a></h4>
|
||||
|
||||
<p>
|
||||
<a name="cpu"> The I/O chip is connected to the 68000 and Z80. When in
|
||||
Mark-III compatibility mode, the I/O chip has a different set of
|
||||
registers which mimic those of the SMS, which will not be discussed
|
||||
here.
|
||||
<br><br>
|
||||
The I/O chip is mapped to $A10000-$A1001F in the 68000/VDP/Z80 banked address space.
|
||||
It is normally read and written in byte units at odd addresses.
|
||||
The chip gets /LWR only, so writing to even addresses has no effect.
|
||||
|
||||
Reading even addresses returns the same data you'd get from an odd address.
|
||||
If a word-sized write is done, the LSB is sent to the I/O chip and the MSB is ignored.
|
||||
Here are some examples to illustrate these points:
|
||||
</a></p><pre><a name="cpu"> ; Does nothing, byte writes to even addresses are ignored
|
||||
move.b #$40, $A10002
|
||||
|
||||
; Returns contents of version register, reading even addresses is the same as reading odd ones
|
||||
move.b $A10000, d0
|
||||
|
||||
; Same as writing #$40 to $A10007, the MSB is ignored
|
||||
move.w #$C040, $A10006
|
||||
</a></pre>
|
||||
<p></p>
|
||||
|
||||
<a name="reg">
|
||||
</a><h4><a name="reg">Register list</a></h4>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>Address</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10001</td>
|
||||
<td>Version</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10003</td>
|
||||
<td>Port A data</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10005</td>
|
||||
<td>Port B data</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10007</td>
|
||||
<td>Port C data</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10009</td>
|
||||
<td>Port A control</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1000B</td>
|
||||
<td>Port B control</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1000D</td>
|
||||
<td>Port C control</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1000F</td>
|
||||
<td>Port A TxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10011</td>
|
||||
<td>Port A RxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10013</td>
|
||||
<td>Port A serial control</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10015</td>
|
||||
<td>Port B TxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10017</td>
|
||||
<td>Port B RxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10019</td>
|
||||
<td>Port B serial control</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1001B</td>
|
||||
<td>Port C TxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1001D</td>
|
||||
<td>Port C RxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1001F</td>
|
||||
<td>Port C serial control</td>
|
||||
</tr>
|
||||
|
||||
</tbody></table>
|
||||
|
||||
<a name="ver">
|
||||
</a><h4><a name="ver">Version register</a></h4>
|
||||
<p>
|
||||
<a name="ver"> The version register returns several types of
|
||||
information, such as a hard-coded version number, settings of the
|
||||
domestic/export and PAL/NTSC jumpers, and the state of a sense pin
|
||||
which the Sega CD uses. </a></p><pre><a name="ver"> D7 : Console is 1= Export (USA, Europe, etc.) 0= Domestic (Japan)
|
||||
D6 : Video type is 1= PAL, 0= NTSC
|
||||
D5 : Sega CD unit is 1= not present, 0= connected.
|
||||
D4 : Unused (always returns zero)
|
||||
D3 : Bit 3 of version number
|
||||
D2 : Bit 2 of version number
|
||||
D1 : Bit 1 of version number
|
||||
D0 : Bit 0 of version number
|
||||
</a></pre>
|
||||
|
||||
<a name="ver"> Bit 5 is used by the Sega CD, returning '0' when it is attached and '1' when it is not.
|
||||
|
||||
<br><br>
|
||||
The version number is zero for the original model Genesis and MegaDrive.
|
||||
All later versions of the hardware are version 1, and have additional security hardware.
|
||||
|
||||
<br><br>
|
||||
Bits 7,6 are used in country protection checks. Some early games used
|
||||
them to display English or Japanese text, so the same game program could
|
||||
be used in both regions. Here's a list of settings:
|
||||
</a><p></p>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>Bit 7</td>
|
||||
<td>Bit 6</td>
|
||||
<td>TV type</td>
|
||||
<td>Region</td>
|
||||
<td>Comments</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>NTSC</td>
|
||||
<td>Japan, Korea, Taiwan</td>
|
||||
<td>262 lines, 60 FPS</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>PAL</td>
|
||||
<td>Japan</td>
|
||||
<td>No hardware actually uses this setting</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>NTSC</td>
|
||||
<td>USA, Canada</td>
|
||||
<td>262 lines, 60 FPS</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>PAL-M</td>
|
||||
<td>Brazil</td>
|
||||
<td>262 lines, 60 FPS</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>PAL</td>
|
||||
<td>Europe, Hong Kong</td>
|
||||
<td>313 lines, 50 FPS</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="ver"> Early games stored a region compatibility code in their
|
||||
header at offset $0001F1. This value could be the ASCII text J, U, or E
|
||||
for Japan, USA or Europe. During game initialization, bits 7,6 could be
|
||||
sampled and compared to the region type stored in the header. If there
|
||||
is a mismatch, many games will fill the screen with a single color lock
|
||||
up intentionally, or sometimes display an error message. <br><br>
|
||||
Later games have a slightly more complex code.
|
||||
Here's the table Sega uses to determine valid codes to use:
|
||||
</a></p>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td colspan="2">$A10001</td>
|
||||
<td> </td>
|
||||
<td rowspan="2">Main Sales Territories</td>
|
||||
<td colspan="16">Hardware Enable Code (numbers from 0 to F below)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#cccccc">
|
||||
<td>Bit 7</td>
|
||||
<td>Bit 6</td>
|
||||
<td>Hardware Type</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
<td>5</td>
|
||||
<td>6</td>
|
||||
<td>7</td>
|
||||
<td>8</td>
|
||||
<td>9</td>
|
||||
<td>A</td>
|
||||
<td>B</td>
|
||||
<td>C</td>
|
||||
<td>D</td>
|
||||
<td>E</td>
|
||||
<td>F</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>Japan, NTSC</td>
|
||||
<td>Japan, S. Korea, Taiwan</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>Japan, PAL</td>
|
||||
<td> </td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>Overseas, NTSC</td>
|
||||
<td>N. America, Brazil</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>Overseas, PAL</td>
|
||||
<td>Europe, Hong Kong</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="ver"> Common uses of the new code type are ASCII values '4' for N.America, 'A' for UK, and 'B' for UK and Japan.
|
||||
</a></p>
|
||||
|
||||
|
||||
<a name="dat">
|
||||
</a><h4><a name="dat">Data register</a></h4>
|
||||
<p>
|
||||
<a name="dat"> Writing to the data register sets the logic level of
|
||||
pins configured as outputs (0= 0V, 1= +5V), and does nothing to pins
|
||||
configured as inputs. Reading from the data register returns the state
|
||||
of each pin. Here's a list of which bits in the data register
|
||||
correspond to pins on the I/O port.
|
||||
</a></p><pre><a name="dat"> D7 : Unused. This bit will return any value written to it
|
||||
D6 : TH pin
|
||||
D5 : TR pin
|
||||
D4 : TL pin
|
||||
D3 : D3 pin
|
||||
D2 : D2 pin
|
||||
D1 : D1 pin
|
||||
D0 : D0 pin
|
||||
</a></pre>
|
||||
|
||||
<a name="dat"> If a pin is configured as an input, reading it returns
|
||||
the true logic state of whatever the pin is connected to (e.g. 0 for
|
||||
ground, 1 for +5V). If nothing is connected to it, the pin returns '1',
|
||||
maybe due to internal pull-up resistors.
|
||||
<br><br>
|
||||
If a pin is configured as an output, reading it returns the last value written to this register.
|
||||
</a><p></p>
|
||||
|
||||
<a name="dir">
|
||||
</a><h4><a name="dir">Control register</a></h4>
|
||||
<p>
|
||||
<a name="dir"> The control register determines which pins are inputs and outputs.
|
||||
|
||||
</a></p><pre><a name="dir"> D7 : /HL output control (see description)
|
||||
D6 : TH pin is 1=output, 0=input
|
||||
D5 : TR pin is 1=output, 0=input
|
||||
D4 : TL pin is 1=output, 0=input
|
||||
D3 : D3 pin is 1=output, 0=input
|
||||
D2 : D2 pin is 1=output, 0=input
|
||||
D1 : D1 pin is 1=output, 0=input
|
||||
D0 : D0 pin is 1=output, 0=input
|
||||
</a></pre>
|
||||
|
||||
<a name="dir"> If bit 7 of this register is set, and TH is configured as an input,
|
||||
then whenever external hardware makes high to low transition on TH
|
||||
the I/O chip will strobe it's /HL output pin low. This pin connects to
|
||||
the VDP, which can be set up to latch the HV counter and/or cause a level 2
|
||||
interrupt upon /HL going low.
|
||||
</a><p></p>
|
||||
|
||||
<a name="scr">
|
||||
</a><h4><a name="scr">Serial control register</a></h4>
|
||||
<p>
|
||||
<a name="scr"> The serial control register defines how a port is used for serial
|
||||
communications and provides status flags to indicate the current state
|
||||
of sending or receiving data.
|
||||
|
||||
</a></p><pre><a name="scr"> D7 : Serial baud rate bit 1
|
||||
D6 : Serial baud rate bit 0
|
||||
D5 : TR pin functions as 1= serial input pin, 0= normal
|
||||
D4 : TL pin functions as 1= serial output pin, 0= normal
|
||||
D3 : 1= Make I/O chip strobe /HL low when a byte has been received, 0= Do nothing
|
||||
D2 : 1= Error receiving current byte, 0= No error
|
||||
D1 : 1= Rxd buffer is ready to read, 0= Rxd buffer isn't ready
|
||||
D0 : 1= Txd buffer is full, 0= Can write to Txd buffer
|
||||
</a></pre>
|
||||
|
||||
<a name="scr"> The available baud rates are:
|
||||
</a><p></p>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>D7</td>
|
||||
<td>D6</td>
|
||||
<td>Baud rate</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>4800 bps</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2400 bps</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>1200 bps</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>300 bps</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="scr"> When doing serial communication, TL and/or TR can be used for sending
|
||||
and receiving data. During this time the data and control registers
|
||||
have no effect for whichever pin(s) are in serial mode. The rest of the
|
||||
pins in the same port function normally.
|
||||
|
||||
<br><br> The intended use of bit 3 is to also have the VDP set up to
|
||||
enable level 2 interrupts when /HL goes low. This way, when the I/O
|
||||
chip receives a byte through the TR pin, if this bit is set then it
|
||||
will strobe /HL low and cause an interrupt. So receiving data serially
|
||||
can either be accomplished through manual polling or be interrupt
|
||||
driven.
|
||||
<br><br>
|
||||
Bits 2-0 are read-only status flags, the rest of the bits in this register can be read and written.
|
||||
</a></p>
|
||||
|
||||
|
||||
<a name="txd">
|
||||
</a><h4><a name="txd">TxData register</a></h4>
|
||||
<p>
|
||||
<a name="txd"> Writing a byte to this register will make the I/O chip
|
||||
output the data serially through the TL pin, providing it was
|
||||
configured for serial mode. You should poll bit 0 of the serial control
|
||||
register until the bit returns 0 to ensure the previously written byte
|
||||
has been sent and the TxData buffer is empty.
|
||||
</a></p>
|
||||
|
||||
<a name="rxd">
|
||||
</a><h4><a name="rxd">RxData register</a></h4>
|
||||
<p>
|
||||
<a name="rxd"> Reading from this register returns the last byte
|
||||
received serially through the TR pin. You should check bits 3,2 of the
|
||||
serial control register to ensure that the RxData input buffer is full
|
||||
and that there were no errors in receiving the byte (which would then
|
||||
be invalid).
|
||||
</a></p>
|
||||
|
||||
<a name="ser">
|
||||
</a><h4><a name="ser">Using serial communication</a></h4>
|
||||
<p>
|
||||
<a name="ser"> When in serial mode, the I/O ports output TTL-level
|
||||
signals. You need something like a MAX232 line driver to convert these
|
||||
to RS-232 compatible signals for interfacing with (for example) a PC.
|
||||
<br><br> If you just want to do experiments on the serial ports
|
||||
themselves, you can use a null modem cable with the TL/TR wires
|
||||
switched around to connect port A to B. I used this for testing the
|
||||
serial capabilities while writing this document. Be sure to disconnect
|
||||
the +5V line as well.
|
||||
</a></p>
|
||||
|
||||
<a name="per">
|
||||
</a><h2><a name="per">Peripheral devices</a><hr></h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#md2">2-button Mark-III gamepad</a>
|
||||
</li><li><a href="#md3">3-button standard gamepad</a>
|
||||
</li><li><a href="#md6">Fighting Pad 6B</a>
|
||||
</li><li><a href="#gun">Lightguns (Sega Menacer, Konami Justifier)</a>
|
||||
</li><li><a href="#eat">EA 4-Way Play</a>
|
||||
</li><li><a href="#mul">Sega Team Player</a>
|
||||
</li><li><a href="#mmo">Sega Mega Mouse</a>
|
||||
</li></ul>
|
||||
|
||||
<a name="md2">
|
||||
</a><h4><a name="md2">2-button Mark-III gamepad</a></h4>
|
||||
<p>
|
||||
<a name="md2"> This controller has a 4-way direction pad, and two buttons (2 and 1).
|
||||
Here's a description of how the controller interfaces with an I/O port:
|
||||
|
||||
</a></p><pre><a name="md2"> D6 : (TH) Not used
|
||||
D5 : (TR) Button 2
|
||||
D4 : (TL) Button 1
|
||||
D3 : (D3) D-pad Right
|
||||
D2 : (D2) D-pad Left
|
||||
D1 : (D1) D-pad Down
|
||||
D0 : (D0) D-pad Up
|
||||
</a></pre>
|
||||
|
||||
<a name="md2"> All buttons are active-low logic, so they return '0' when pressed and '1' when released.
|
||||
</a><p></p>
|
||||
|
||||
<a name="md3">
|
||||
</a><h4><a name="md3">3-button standard gamepad</a></h4>
|
||||
<p>
|
||||
<a name="md3"> This controller has a 4-way direction pad, and four buttons (Start, A, B, C).
|
||||
It uses a multiplexer that selects 1 of 2 inputs using TH, and routes buttons Start or C to TR, and B or A to TL.
|
||||
|
||||
<br><br>
|
||||
Here's a description of how the controller interfaces with an I/O port:
|
||||
|
||||
</a></p><pre><a name="md3"> When TH=0 When TH=1
|
||||
D6 : (TH) 0 1
|
||||
D5 : (TR) Start button Button C
|
||||
D4 : (TL) Button A Button B
|
||||
D3 : (D3) 0 D-pad Right
|
||||
D2 : (D2) 0 D-pad Left
|
||||
D1 : (D1) D-pad Down D-pad Down
|
||||
D0 : (D0) D-pad Up D-pad Up
|
||||
</a></pre>
|
||||
|
||||
<a name="md3"> All buttons are active-low logic, so they return '0' when pressed and '1' when released.
|
||||
|
||||
<br><br> You need a small delay between changing TH and reading the
|
||||
button state back, as the multiplexer takes some time in switching
|
||||
inputs. I've found about four NOPs provides a reasonable delay.
|
||||
<br><br>
|
||||
Here's some example code to read a 3-button gamepad:
|
||||
</a><p></p>
|
||||
|
||||
<table bgcolor="#e0e0e0" width="70%"><tbody><tr><td><pre>; Returns D0 with the button states: 'SACBRLDU'
|
||||
_read_joypad:
|
||||
move.l d1, -(a7)
|
||||
move.b #$40, $A10003
|
||||
nop
|
||||
nop
|
||||
move.b $A10003, d0
|
||||
andi.b #$3F, d0
|
||||
move.b #$00, $A10003
|
||||
nop
|
||||
nop
|
||||
move.b $A10003, d1
|
||||
lsl.b #2, d1
|
||||
andi.b #$C0, d1
|
||||
or.b d1, d0
|
||||
eori.b #$FF, d0
|
||||
move.l (a7)+, d1
|
||||
rts
|
||||
</pre></td></tr></tbody></table>
|
||||
|
||||
<a name="md6">
|
||||
</a><h4><a name="md6">Fighting Pad 6B</a></h4>
|
||||
<p>
|
||||
<a name="md6"> Information coming soon.
|
||||
</a></p>
|
||||
|
||||
<a name="gun">
|
||||
</a><h4><a name="gun">Lightguns (Sega Menacer, Konami Justifier)</a></h4>
|
||||
<p>
|
||||
<a name="gun"> Information coming soon.
|
||||
</a></p>
|
||||
|
||||
<a name="eat">
|
||||
</a><h4><a name="eat">EA 4-Way Play</a></h4>
|
||||
<p>
|
||||
<a name="eat"> The EA 4-Way Play plugs into ports A and B, and allows up to four standard Genesis controllers to be connected at once.
|
||||
|
||||
<br><br> I've determined how the multitap works by examining the
|
||||
joystick reading code from NHL '95 and trying the same routine on a
|
||||
new-style Sega Team Player in 'EXTRA' mode. That said, the actual EA
|
||||
4-Way Play could have some differences that Sega's compatibility mode
|
||||
doesn't take care of.
|
||||
<br><br> To detect the multitap, set CTRL1 to 0x40, CTRL2 to 0x7F and
|
||||
DATA2 to $7C. Reading the lower 2 bits of DATA1 will return zero if the
|
||||
multitap is present. Usually these bits return 0x03 if there is no tap,
|
||||
no controller, or the Sega Team Player isn't in EXTRA mode, but this
|
||||
could be a behavior specific to the Team Player.
|
||||
<br><br>
|
||||
To read the pads, write 0x0C, 0x1C, 0x2C, or 0x3C to DATA2 to select the controller in port A, B, C, or D.
|
||||
You can then use DATA1/CTRL1 to read the pad state just like polling a regular 3-button pad in port A.
|
||||
|
||||
<br><br>
|
||||
Here's some example code to use the EA 4-Way Play:
|
||||
</a></p>
|
||||
|
||||
<table bgcolor="#e0e0e0" width="70%"><tbody><tr><td><pre>; Returns D0 == 0 if the multitap is present, or D0 != 0 if it isn't
|
||||
_detect_4wayplay:
|
||||
move.b #$40, $A10009
|
||||
nop
|
||||
move.b #$7F, $A1000B
|
||||
nop
|
||||
move.b #$7C, $A10005
|
||||
nop
|
||||
moveq #0, d0
|
||||
move.b $A10003, d0
|
||||
andi.b #$03, d0
|
||||
rts
|
||||
|
||||
; Returns the state of all four 3-button gamepads in D0
|
||||
_read_4wayplay:
|
||||
move.l d1-d3/a0, -(a7)
|
||||
lea $A10000, a0
|
||||
move.l #$0C1C2C3C, d2
|
||||
moveq #$03, d3
|
||||
poll: move.b d2, $05(a0)
|
||||
nop
|
||||
nop
|
||||
move.b #$40, $03(a0)
|
||||
nop
|
||||
nop
|
||||
move.b $A10003, d0
|
||||
andi.b #$3F, d0
|
||||
move.b #$00, $03(a0)
|
||||
nop
|
||||
nop
|
||||
move.b $03(a0), d1
|
||||
lsl.b #2, d1
|
||||
andi.b #$C0, d1
|
||||
or.b d1, d0
|
||||
lsl.l #8, d0
|
||||
lsr.l #8, d2
|
||||
dbra d3, poll
|
||||
eori.l #-1, d0
|
||||
move.l (a7)+, d2-d3/a0
|
||||
rts
|
||||
</pre></td></tr></tbody></table>
|
||||
|
||||
|
||||
<a name="mul">
|
||||
</a><h4><a name="mul">Sega Team Player</a></h4>
|
||||
<p>
|
||||
<a name="mul"> The Team Player is a multitap device that allows four peripherals to be connected to the Genesis at one time.
|
||||
It has a mode select switch with several settings:
|
||||
</a></p><pre><a name="mul"> EXTRA - All four ports are enabled. This is the setting used by
|
||||
EA 4-Way Play compatible games.
|
||||
A - Routes the peripheral in port A to port A of the Genesis.
|
||||
B - Routes the peripheral in port B to port A of the Genesis.
|
||||
C - Routes the peripheral in port C to port A of the Genesis.
|
||||
D - Routes the peripheral in port D to port A of the Genesis.
|
||||
MULTI - All four ports are enabled. This is the setting used by
|
||||
Team Player compatible games.
|
||||
</a></pre>
|
||||
<a name="mul"> Sega made two versions of the Team Player. The first one
|
||||
was not compatible with the EA 4-Way Play and only had one cable to
|
||||
connect it to port A. The second one added the "EXTRA" setting for EA
|
||||
4-Way Play compatibility and provides a second cable to connect it to
|
||||
port B as well. Both seem to function identically with the exception of
|
||||
EXTRA mode.
|
||||
<br><br>
|
||||
I don't have any programming information for this device.
|
||||
</a><p></p>
|
||||
|
||||
<a name="mmo">
|
||||
</a><h4><a name="mmo">Sega Mega Mouse</a></h4>
|
||||
<p>
|
||||
<a name="mmo"> This is a three button mouse (left, middle, right) with an extra button
|
||||
(Start) located near the thumb position. It uses a PIC16C54 microcontroller
|
||||
which manages the buttons and position tracking.
|
||||
|
||||
<br><br>
|
||||
The Sega Mega Mouse that is distributed in North America is incompatible with the European version of Populous 2.
|
||||
The mouse functions normally but has Y axis inverted so up is down and vice-versa.
|
||||
It may have been designed for the Japanese Mega Drive mouse, which is a <b>different</b> product with 2 buttons and unique physical appearance.
|
||||
|
||||
<br><br>
|
||||
The protocol works as follows:
|
||||
TH and TR are outputs which tell the microcontroller to stop or start a data transfer, and to acknowledge received data.
|
||||
TL is an input which returns a busy flag for the microcontroller.
|
||||
D3-D0 are inputs that return the data.
|
||||
Here's a table showing the communication process:
|
||||
</a></p>
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>Write</td>
|
||||
<td>TH</td>
|
||||
<td>TR</td>
|
||||
<td>TL</td>
|
||||
<td>D3</td>
|
||||
<td>D2</td>
|
||||
<td>D1</td>
|
||||
<td>D0</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$60</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>Request data</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>ID #0 ($0)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>ID #1 ($B)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>ID #2 ($F)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>ID #3 ($F)</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>Y Over</td>
|
||||
<td>X Over</td>
|
||||
<td>Y Sign</td>
|
||||
<td>X Sign</td>
|
||||
<td>Axis sign and overflow</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>Start</td>
|
||||
<td>Middle</td>
|
||||
<td>Right</td>
|
||||
<td>Left</td>
|
||||
<td>Button state</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>X7</td>
|
||||
<td>X6</td>
|
||||
<td>X5</td>
|
||||
<td>X4</td>
|
||||
<td>X axis MSN</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>X3</td>
|
||||
<td>X2</td>
|
||||
<td>X1</td>
|
||||
<td>X0</td>
|
||||
<td>X axis LSN</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>Y7</td>
|
||||
<td>Y6</td>
|
||||
<td>Y5</td>
|
||||
<td>Y4</td>
|
||||
<td>Y axis MSN</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>Y3</td>
|
||||
<td>Y2</td>
|
||||
<td>Y1</td>
|
||||
<td>Y0</td>
|
||||
<td>Y axis LSN</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="mmo"> Write #$60 when you are done polling to stop the data
|
||||
transfer. If you continue to poll the mouse after collecting all the
|
||||
data by writing $20 / $00, the Y axis LSN will always be returned. Sega
|
||||
advises polling beyond this point will make the mouse behave
|
||||
abnormally. It's possible that the PIC code in some versions of the
|
||||
Mega Mouse may have problems if the poll sequence is too long.
|
||||
<br><br>
|
||||
The X/Y overflow flags are supposed to be set if the mouse is moved over a distance greater than can be measured.
|
||||
I can't get them to become set, maybe the mouse supports a fairly wide range of movement.
|
||||
|
||||
|
||||
<br><br> You need a considerable delay between writing new values to
|
||||
TH/TR. I think the intention is to poll TL until the microcontroller
|
||||
returns 'not busy', but I can't get this to work reliably. Sega's mouse
|
||||
reading code also has a timeout when checking TL which would indicate
|
||||
it may get stuck in a certain state.
|
||||
<br><br>
|
||||
All buttons (start, left, middle, right) are active-high logic, so they return '1' when pressed and '0' when released.
|
||||
</a></p>
|
||||
|
||||
<a name="msc">
|
||||
</a><h4><a name="msc">Miscellaneous</a></h4>
|
||||
<p>
|
||||
<a name="msc"> After power-up, the default state of the I/O chip are as follows:
|
||||
</a></p><pre><a name="msc"> $A10001 = $80 (Bits 7,6,5 depend on the domestic/export, PAL/NTSC jumpers and having a Sega CD or not)
|
||||
$A10003 = $7F
|
||||
$A10005 = $7F
|
||||
$A10007 = $7F
|
||||
$A10009 = $00
|
||||
$A1000B = $00
|
||||
$A1000D = $00
|
||||
$A1000F = $FF
|
||||
$A10011 = $00
|
||||
$A10013 = $00
|
||||
$A10015 = $FF
|
||||
$A10017 = $00
|
||||
$A10019 = $00
|
||||
$A1001B = $FB
|
||||
$A1001D = $00
|
||||
$A1001F = $00
|
||||
</a></pre>
|
||||
<p></p>
|
||||
|
||||
<a name="dis">
|
||||
</a><h4><a name="dis">Disclaimer</a></h4>
|
||||
<pre><a name="dis"> If you use any information from this document, please credit me
|
||||
(Charles MacDonald) and optionally provide a link to my webpage
|
||||
(http://cgfm2.emuviews.com/) so interested parties can access it.
|
||||
|
||||
The credit text should be present in the accompanying documentation of
|
||||
whatever project which used the information, or even in the program
|
||||
itself (e.g. an about box)
|
||||
|
||||
Regarding distribution, you cannot put this document on another
|
||||
website, nor link directly to it.
|
||||
</a></pre>
|
||||
|
||||
<hr>
|
||||
|
||||
</body></html>
|
340
docs/license
Normal file
340
docs/license
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
40
docs/m5hvc.txt
Normal file
40
docs/m5hvc.txt
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
VDP timing for an NTSC Genesis in display mode 5.
|
||||
Version 0.4 (11/29/00)
|
||||
|
||||
by Charles MacDonald
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Unpublished work Copyright 2000 Charles MacDonald
|
||||
|
||||
Description 32-cell 40-cell
|
||||
----------------------------------------------------------------------------
|
||||
Range 00-93, E9-FF 00-B6, E4-FF
|
||||
Display area 00-7F 00-9F
|
||||
V counter increment 84, 85 A4, A5
|
||||
V-blanking in 86, 87 A7, A8
|
||||
V-blanking out 86, 87 A7, A8
|
||||
H-blanking in 93, E9 B2, E4
|
||||
H-blanking out 06, 07 06, 07
|
||||
|
||||
Comma seperated values show the H counter value before an event occurs,
|
||||
and then the H counter value immediately after.
|
||||
|
||||
These values shouldn't be considered 100% accurate, they are probably
|
||||
off by one or two.
|
||||
|
||||
Each H counter unit is equivalent to two pixels.
|
||||
|
||||
The gaps at 93-E9 and B6-E4 are where the H counter 'jumps' ahead.
|
||||
The H counter will never actually be set to the values 94-E8 or B7-E3.
|
||||
Perhaps this is the horizontal retrace period.
|
||||
|
||||
Interestingly enough, the timing values for the 32-cell display mode
|
||||
are identical to that of the SMS.
|
||||
|
||||
It would appear that in 40-cell mode, the horizontal blanking period
|
||||
is shorter as the active display period takes more time.
|
||||
|
||||
The V-blanking flag can also be forcibly set by disabling the display
|
||||
through bit 6 of register #1.
|
||||
|
105
docs/newreg.txt
Normal file
105
docs/newreg.txt
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
After some testing, it turns out that the unused VDP address $C0001C
|
||||
(mirrored at $C0001E) controls how the VDP generates the display.
|
||||
|
||||
Specifically, it allows layers to be turned on and off, it affects how
|
||||
high priority sprites or tiles are interpreted, and it seems to change
|
||||
how layers are combined together.
|
||||
|
||||
No games use this register to my knowledge, maybe it was left in for
|
||||
testing or debugging purposes by the VDP manufacturer. This was all
|
||||
checked on an original model Genesis, the register may not be present
|
||||
or behave differently in later versions of the VDP hardware.
|
||||
|
||||
Here's the layout of $C0001C/$C0001E:
|
||||
|
||||
MSB LSB
|
||||
-gfe ---d cba- ----
|
||||
|
||||
Notes:
|
||||
|
||||
Unmarked bits have no effect.
|
||||
Anything pertaining to plane A also applies to the window layer.
|
||||
Any description about color intensity changes is only valid when
|
||||
the VDP is in shadow/hilight mode.
|
||||
|
||||
a = Display garbage (bad pattern data) on all background rows
|
||||
and for the sprites.
|
||||
|
||||
b = Turn display off (background and sprites)
|
||||
Display is filled with background color.
|
||||
CRAM data is randomly corrupted as long as this bit is set.
|
||||
|
||||
c = Turn display off (background only)
|
||||
In shadow/hilight mode, high priority tiles are also invisble
|
||||
but are drawn in the regular normal intensity backdrop color,
|
||||
while low priority tiles are drawn in the half intensity
|
||||
backdrop color.
|
||||
Transparent pixels in high priority sprites are also filled
|
||||
with the normal intensity backdrop color, so sprites have
|
||||
a tile shaped outline around them.
|
||||
It seems like either underlying pixels from the background
|
||||
are visible through shadow/hilight pixels in sprites, but
|
||||
the colors are wrong. (as if they were logically OR'd with
|
||||
the sprite pixels, as both layers can be seen)
|
||||
CRAM data is randomly corrupted as long as this bit is set.
|
||||
|
||||
** When 'c' and 'b' are set, the background layers are invisible,
|
||||
but sprites are not. All sprites, regardless of priority,
|
||||
have a tile shaped outline around them that is drawn in some
|
||||
color other than the backdrop color. (can't exactly tell)
|
||||
|
||||
d = When set, garbage is displayed in the top and bottom border areas.
|
||||
Plane B is disabled, only plane A is visible.
|
||||
All sprites are drawn in the regular intensity backdrop color.
|
||||
High priority plane B tiles are drawn in the regular intensity
|
||||
background color, low priority plane B tiles are drawn in the
|
||||
half intensity backdrop color.
|
||||
|
||||
g,f,e = All bits turn off sprites when set.
|
||||
If bit 'd' is set, bit 'e' changes the garbage data printed
|
||||
in the border areas.
|
||||
|
||||
Bits b,c,d have effects when combined, as the following table
|
||||
shows. Some of this information is a rehash of what was explained
|
||||
above. Bits g,f,e will turn off sprites in all cases. (unless they
|
||||
are already off to begin with)
|
||||
|
||||
Notes:
|
||||
RI = regular intensity backdrop color
|
||||
HI = half intensity backdrop color
|
||||
A,B,S = Plane A, plane B, sprite layer
|
||||
|
||||
b c d Effect
|
||||
----- ------
|
||||
0 0 0 Display shown normally
|
||||
0 0 1 B and S off, high priority pixels from B and S drawn in RI
|
||||
0 1 0 A and B off, high priority pixels from A and S drawn in RI, sprites
|
||||
have tile-shaped outline in RI.
|
||||
0 1 1 Plane A pixels seem to be OR'd with plane B pixels, and the
|
||||
output is OR'd with the sprite pixels.
|
||||
1 0 0 A, B, and S off
|
||||
1 0 1 B and S off, shadow/hilight mode off
|
||||
1 1 0 A and B off, sprites have tile shaped outline in unknown color.
|
||||
1 1 1 A and S off, shadow/hilight mode off
|
||||
|
||||
In mode 4, the same results apply with the following exceptions:
|
||||
|
||||
- Shadow/hilight processing is always off
|
||||
|
||||
- Anything that enables plane B seems to turn on a second graphics
|
||||
layer, which is identical to plane A with garbage data. (so the VDP
|
||||
can't really create two playfields in mode 4, but it does seem
|
||||
to try to re-use plane A with bad graphics)
|
||||
The settings which seem to enable plane B are when
|
||||
bits b,c,d are 1,1,1, and and 0,1,1.
|
||||
|
||||
- The leftmost 8 pixels show a lot of garbage data when some of the
|
||||
bits are set. (seems unrelated to sprites or background)
|
||||
Earlier it was discovered that the VDP doesn't draw the background
|
||||
tile in the left 8 pixels when the lower 3 bits of the horizontal
|
||||
scroll value are not equal to zero, it shows garbage data that seems
|
||||
to be based on the sprite positions. Also, this can be seen in the
|
||||
rightmost 8 columns if you enable 40-cell mode while in mode 4, so
|
||||
the resulting display is 320x192.
|
||||
|
89
docs/porting.txt
Normal file
89
docs/porting.txt
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
Introduction
|
||||
|
||||
Genesis Plus has reasonable speed, and very fast rendering. Here are some
|
||||
details about porting it to another platform
|
||||
|
||||
Porting rules
|
||||
|
||||
- This program is released under the GPL, so please release the source
|
||||
code for your derivative ports. Let me know if you need an alternative
|
||||
to this.
|
||||
|
||||
- Do not change the name of the emulator. Something like 'Genesis Plus / MacOS'
|
||||
is fine as it keeps the original name.
|
||||
|
||||
- Configure the CPU emulators for little or big-endian CPUs, and use the
|
||||
ALIGN_LONG option to handle unaligned memory accesses if needed. E.g. if
|
||||
the emulator crashes when a game scrolls horizontally, you need to enable
|
||||
it.
|
||||
|
||||
Requirements
|
||||
|
||||
- At this time the 16-bit rendering code has been well tested and should
|
||||
be used. There is code to support 8 through 32-bit displays, but I
|
||||
haven't checked if it still works.
|
||||
|
||||
- Audio output, if enabled, uses stereo 16-bit samples.
|
||||
|
||||
Functions to use:
|
||||
|
||||
int load_rom(char *filename);
|
||||
|
||||
Loads a game which can be in BIN, SMD or ZIP formats. It returns zero if
|
||||
an error has occured.
|
||||
|
||||
void system_init(void);
|
||||
|
||||
Initializes the virtual Genesis console. Call this once during startup.
|
||||
|
||||
void audio_init(int rate);
|
||||
|
||||
Initialize the sound emulation part of the emulator. Pass zero or don't
|
||||
call the function to disable sound. Call this after running system_init().
|
||||
|
||||
void system_reset(void);
|
||||
|
||||
Resets the virtual Genesis console. Call this once during setup, and later
|
||||
as needed.
|
||||
|
||||
int system_frame(int skip);
|
||||
|
||||
Updates the emulation for a frame. Pass 1 to prevent rendering (which can
|
||||
be used for frame skipping) and 0 to render the current display.
|
||||
|
||||
This function returns 0 if the virtual Genesis console has locked up.
|
||||
You can do what you'd like with this information, such as notify the user,
|
||||
reset the machine, etc.
|
||||
|
||||
If audio is enabled, the snd.buffer[] array will hold the current audio
|
||||
data for this frame.
|
||||
|
||||
void system_shutdown(void);
|
||||
|
||||
Shuts down the emulator.
|
||||
|
||||
Variables:
|
||||
|
||||
The 'bitmap' structure needs to be filled out prior to calling system_init().
|
||||
This provides the rendering code with information about the type of bitmap
|
||||
it is rendering to. I would advise sticking with a 1024x512 16-bit bitmap:
|
||||
|
||||
memset(&bitmap, 0, sizeof(t_bitmap));
|
||||
bitmap.width = 1024;
|
||||
bitmap.height = 512;
|
||||
bitmap.depth = 16;
|
||||
bitmap.granularity = 2; /* Bytes per pixel */
|
||||
bitmap.pitch = (bitmap.width * bitmap.granularity);
|
||||
bitmap.data = (unsigned char *)bmp->pixels; /* Pointer to your bitmap */
|
||||
bitmap.viewport.w = 256; /* Initial size of display on power-up (do not change) */
|
||||
bitmap.viewport.h = 224;
|
||||
bitmap.viewport.x = 0x20; /* Offset used for rendering (do not change) */
|
||||
bitmap.viewport.y = 0x00;
|
||||
bitmap.remap = 1;
|
||||
|
||||
The variable 'input.pad[0]' holds the button states for the first player
|
||||
gamepad. Update this prior to calling system_frame(), and use the bitmasks
|
||||
defined in system.h such as 'INPUT_UP', etc.
|
||||
|
||||
See the Windows/SDL and DOS drivers for examples.
|
122
docs/readme.txt
Normal file
122
docs/readme.txt
Normal file
@ -0,0 +1,122 @@
|
||||
----------------------------------------------------------------------------
|
||||
Genesis Plus
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Version 1.2a
|
||||
by Charles Mac Donald
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
What's New
|
||||
----------
|
||||
|
||||
[06/22/03]
|
||||
- Modified rendering code for portability
|
||||
- Modified memory handling to fix banked PSG access
|
||||
[05/13/03]
|
||||
- Initial release
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The Windows version runs windowed in a 16-bit desktop with NO sound or
|
||||
joystick support.
|
||||
|
||||
The DOS version has most of the functionality from SMS Plus, such
|
||||
as audio, joysticks, etc.
|
||||
|
||||
Windows/DOS controls:
|
||||
|
||||
Arrow Keys - Directional pad
|
||||
A,S,D,F - 1P gamepad, buttons A, B, C, Start
|
||||
Tab - Reset
|
||||
Esc - Exit program
|
||||
|
||||
DOS only:
|
||||
|
||||
End - Exit program
|
||||
F1-F4 - Set frameskip level (F1 = no skip ... F4 = skip 3 frames)
|
||||
F8 - Make PCX screen snapshot
|
||||
F9 - Toggle VSync
|
||||
F10 - Toggle speed throttling
|
||||
F11 - Toggle FPS meter
|
||||
|
||||
DOS details:
|
||||
|
||||
You can only support a second player if you are using a joystick driver
|
||||
that supports more than one joystick. (e.g. Sidewinder, dual pads, etc.)
|
||||
|
||||
Type 'gen -help' on the command line for a list of useful options.
|
||||
|
||||
-res <x> <y> set the display resolution.
|
||||
-vdriver <n> specify video driver.
|
||||
-depth <n> specify color depth. (8, 16)
|
||||
-scanlines use scanlines effect.
|
||||
-scale scale display to full resolution. (slow)
|
||||
-vsync wait for vertical sync before blitting.
|
||||
-sound enable sound. (force speed throttling)
|
||||
-sndrate <n> specify sound rate. (8000, 11025, 22050, 44100)
|
||||
-sndcard <n> specify sound card. (0-7)
|
||||
-swap swap left and right stereo output.
|
||||
-joy <s> specify joystick type.
|
||||
|
||||
Here is a list of all the video drivers you can pass as a parameter
|
||||
to the '-vdriver' option:
|
||||
|
||||
auto, safe, vga, modex, vesa2l, vesa3, vbeaf
|
||||
|
||||
Here is a list of all the joystick drivers you can pass as a parameter
|
||||
to the '-joy' option:
|
||||
|
||||
auto, none, standard, 2pads, 4button, 6button, 8button, fspro, wingex,
|
||||
sidewinder, gamepadpro, grip, grip4, sneslpt1, sneslpt2, sneslpt3,
|
||||
psxlpt1, psxlpt2, psxlpt3, n64lpt1, n64lpt2, n64lpt3, db9lpt1, db9lpt2,
|
||||
db9lpt3, tglpt1, tglpt2, tglpt3, wingwar, segaisa, segapci, segapci2
|
||||
|
||||
You can put any commandline option into a plain text file which should
|
||||
be called "gen.cfg". Put one option per line, please. Command line options
|
||||
will override anything in the configuration file.
|
||||
|
||||
Currently the zip loading code can manage a zipfile where the game
|
||||
image is the first thing in it. If you try to open a huge archive of
|
||||
games, only the first will be played.
|
||||
|
||||
Credits and Acknowlegements
|
||||
---------------------------
|
||||
|
||||
I would like to thank Omar Cornut, Christian Schiller, and Chris MacDonald
|
||||
for their invaluable help and support with this project.
|
||||
|
||||
Richard Bannister for the Macintosh port and all of the code fixes and
|
||||
suggestions that have made Genesis Plus a better program.
|
||||
(http://www.bannister.org)
|
||||
|
||||
The Genesis emulator authors: Bart Trzynadlowski, Quintesson, Steve Snake,
|
||||
James Ponder, Stef, Gerrie, Sardu.
|
||||
|
||||
The regular people and many lurkers at segadev.
|
||||
|
||||
The MAME team for the CPU and sound chip emulators.
|
||||
|
||||
Everyone who has contributed, donated, and submitted information to help
|
||||
out Genesis Plus and my efforts documenting the Genesis hardware.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
Charles MacDonald
|
||||
E-mail: cgfm2@hotmail.com
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Legal
|
||||
-----
|
||||
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
||||
|
||||
The source code is distributed under the terms of the GNU General Public
|
||||
License.
|
||||
|
||||
The Z80 CPU emulator, 68K CPU emulator, and the PSG, YM2612 emulation code
|
||||
are taken from the MAME project, and terms of their use are covered under
|
||||
the MAME license.
|
||||
(http://www.mame.net)
|
||||
|
189
docs/ssf2tnc.txt
Normal file
189
docs/ssf2tnc.txt
Normal file
@ -0,0 +1,189 @@
|
||||
---------------------------------------
|
||||
SSFII GENESIS TECHNICAL INFORMATION
|
||||
Second Edition (July 26, 2000)
|
||||
Bart Trzynadlowski
|
||||
---------------------------------------
|
||||
|
||||
|
||||
The purpose of this document is to discuss the workings of the Genesis port of
|
||||
Capcom's "Super Street Fighter II The New Challengers". Virtually all of this
|
||||
information was originally found by others' efforts.
|
||||
Please credit "those who contributed information" rather than me if
|
||||
you use any of this information. You may pass this document around freely, but
|
||||
please keep it unaltered. If you see any errors or have more info, contact me.
|
||||
I can be reached at trzy@powernet.net.
|
||||
|
||||
Second Edition: July 26, 2000
|
||||
- Major update with correct information thanks to Tim Meekins
|
||||
First Edition: July 21, 2000
|
||||
- Initial release
|
||||
|
||||
|
||||
0. THE SSFII CHALLENGE
|
||||
|
||||
The challenge behind getting "Super Street Fighter II The New Challengers"
|
||||
(SSFII) to work on a Genesis emulator lies primarily in the fact that the game
|
||||
is stored on a 40 megabit (5 megabyte) cartridge.
|
||||
The Sega Genesis maps ROM from 0x000000 to 0x3FFFFF which means that
|
||||
the CPU can only see 4 megabytes of cartridge ROM. SSFII needed more space for
|
||||
the backgrounds and thus Capcom opted for a special 5 megabyte cartridge with
|
||||
bankswitching in order to access the area of ROM outside of normal range.
|
||||
|
||||
|
||||
1. THE BANKSWITCHING MECHANISM
|
||||
|
||||
The bankswitching mechanism probably resides on the cartridge. I'm 99% sure of
|
||||
this. Sega documentation does offer a description of the mechanism, though,
|
||||
which led me to suspect for a moment that perhaps the mechanism was on the
|
||||
Genesis itself.
|
||||
The idea is unlikely though, as that range of registers is used by the
|
||||
32X for an entirely different purpose. I have been informed that that range
|
||||
(which is marked as "SEGA RESERVED" in the Genesis developer's manual) can be
|
||||
used for extra devices which may be present on the cartridge.
|
||||
|
||||
The bankswitching mechanism is very simple. It views the addressable 4 mega-
|
||||
bytes of ROM as 8 512KB regions. The first area, 0x000000-0x07FFFF is fixed
|
||||
and cannot be remapped because that is where the vector table resides.
|
||||
The banking registers on the cartridge work by allocating the 512KB
|
||||
chunk to a given part of the addressable 4MB ROM space. Below are the
|
||||
registers and what range they correspond to. The value written to a register
|
||||
will cause the specified 512KB page to be mapped to that region. A page is
|
||||
specified with 6 bits (bits 7 and 6 are always 0) thus allowing a possible 64
|
||||
pages (SSFII only has 10, though.)
|
||||
|
||||
0xA130F3: 0x080000 - 0x0FFFFF
|
||||
0xA130F5: 0x100000 - 0x17FFFF
|
||||
0xA130F7: 0x180000 - 0x1FFFFF
|
||||
0xA130F9: 0x200000 - 0x27FFFF
|
||||
0xA130FB: 0x280000 - 0x2FFFFF
|
||||
0xA130FD: 0x300000 - 0x37FFFF
|
||||
0xA130FF: 0x380000 - 0x3FFFFF
|
||||
|
||||
The registers are accessed through byte writes. I haven't seen SSFII try to
|
||||
read any of the registers, so I don't know if it's possible or not. I don't
|
||||
emulate anything besides byte writes in my emulator.
|
||||
There is also a register 0xA130F1. Apparently the regions specified by
|
||||
0xA130F9-0xA130FF (0x200000-0x3FFFFF) can be either ROM or RAM and can be
|
||||
write-protected. Here is the layout of the register as far as I know:
|
||||
|
||||
7 6 5 4 3 2 1 0
|
||||
+-----------------------+
|
||||
|??|??|??|??|??|??|WP|MD|
|
||||
+-----------------------+
|
||||
|
||||
MD: Mode -- 0 = ROM, 1 = RAM
|
||||
WP: Write protect -- 0 = writable, 1 = not writable
|
||||
|
||||
Emulation of the 0xA130F1 register is not necessary, SSFII initializes it at
|
||||
start-up by writing 0 I believe, which signifies ROM and no write protection
|
||||
to the regions at 0x200000-0x3FFFFF (ROM isn't writable anyway, there isn't a
|
||||
need for protection.)
|
||||
|
||||
Examples:
|
||||
|
||||
If 0x01 is written to register 0xA130FF, 0x080000-0x0FFFFF is visible
|
||||
at 0x380000-0x3FFFFF.
|
||||
If 0x08 is written to register 0xA130F9, the first 512KB of the
|
||||
normally invisible upper 1MB of ROM is now visible at 0x200000-
|
||||
0x27FFFF.
|
||||
|
||||
The registers simply represent address ranges in the 4MB ROM area and you can
|
||||
page in data to these ranges by specifying the bank # -- it's that simple!
|
||||
|
||||
|
||||
2. CHECKSUM
|
||||
|
||||
SSFII contains a checksum routine which calculates the checksum of the first
|
||||
4MB of the ROM; it then pages in the last 1MB of ROM to 0x300000-0x3FFFFF.
|
||||
It does this by writing to the bank registers. The following code is taken
|
||||
directly from the US ROM dumped by Genesis Power:
|
||||
|
||||
... Checksum first 4MB of ROM (0x000000-0x3FFFFF) ...
|
||||
0x003BEC: move.b #$08, ($A130FD)
|
||||
0x003BF4: move.b #$09, ($A130FF)
|
||||
0x003BFC: lea ($300000), a0
|
||||
... Checksum uppper 1MB of ROM now mapped at 0x300000-0x3FFFFF ...
|
||||
|
||||
The bankswitching hardware must be properly emulated before the game starts
|
||||
working. If it is not, the checksum will fail and the game will hang with a
|
||||
red screen.
|
||||
In the Genesis Power US dump, you can jump to 0x003C3C to avoid the
|
||||
checksum routine, this is where program flow transfers to if the checksum was
|
||||
found to be valid. The game doesn't do anything important before the checksum
|
||||
code as far as emulation is concerned. It writes the SEGA message to the
|
||||
Trademark Security System register and does some joypad init stuff.
|
||||
|
||||
|
||||
3. EMULATING SSFII
|
||||
|
||||
SSFII is fairly straightforward to emulate. All you need to do is detect the
|
||||
game, load up all 5MB, and emulate the banking registers. The easiest way to
|
||||
do it, in my opinion, is to keep a second copy of the ROM and do memcpy()s
|
||||
from that second copy to the ROM being emulated.
|
||||
|
||||
For example, here is how Genital does it... I've got genesis.rom which is the
|
||||
buffer where ROMs are loaded and executed. There is also genesis.rom_ssf2
|
||||
which is another 5MB buffer where I load the SSFII ROM to as well.
|
||||
The bankswitching register emulation is done in my IOWriteByte()
|
||||
function (which handles byte writes to the 0xA00000-0xBFFFFF range). The
|
||||
following is the code I use:
|
||||
|
||||
if (addr >= 0xa130f3 && config.ssf2_emu)
|
||||
{
|
||||
switch (addr & 0xf)
|
||||
{
|
||||
case 0x3: /* 080000-0FFFFF */
|
||||
memcpy((genesis.rom + 0x080000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0x5: /* 100000-17FFFF */
|
||||
memcpy((genesis.rom + 0x100000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0x7: /* 180000-1FFFFF */
|
||||
memcpy((genesis.rom + 0x180000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0x9: /* 200000-27FFFF */
|
||||
memcpy((genesis.rom + 0x200000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0xb: /* 280000-2FFFFF */
|
||||
memcpy((genesis.rom + 0x280000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0xd: /* 300000-37FFFF */
|
||||
memcpy((genesis.rom + 0x300000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0xf: /* 380000-3FFFFF */
|
||||
memcpy((genesis.rom + 0x380000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Pardon the bad formatting, it just wouldn't fit correctly in the 80 columns
|
||||
that the rest of the document sticks to.
|
||||
The first line checks whether the address is 0xA130F3 or above (notice
|
||||
how 0xA130F1 is ignored, SSFII doesn't really use it) and if SSFII emulation
|
||||
is enabled (in Genital, I have a flag -- config.ssf2_emu -- which is set to 1
|
||||
to indicate SSFII emulation should occur.) The remainder of the code is a
|
||||
switch () statement which handles the register emulation.
|
||||
Since 0x80000 = 512KB, and the data variable holds the byte written to
|
||||
the register, data * 0x80000 yields the offset into the ROM that has been
|
||||
requested to be mapped.
|
||||
At first glance, memcpy()s may seem inefficient and slow. Although it
|
||||
is true, this doesn't apply to emulating SSFII since the game doesn't do much
|
||||
(if any) bankswitching during gameplay. No slowdown due to the memcpy()s is
|
||||
noticable.
|
||||
|
||||
If you are using an emulator like Starscream which requires the ROMs to be
|
||||
byteswapped, make certain both ROM images are byteswapped. If you don't use
|
||||
2 copies of the ROM, you will find the game will still have several glitches
|
||||
because the memcpy()s will be destroying the data they write over.
|
||||
|
||||
|
||||
4. CONCLUSION
|
||||
|
||||
That's all there is to it. This should be sufficient information for anyone
|
||||
wishing to implement SSFII support in their Sega Genesis emulator. If you have
|
||||
any questions at all (I'm not great at making things clear) feel free to email
|
||||
me at trzy@powernet.net.
|
||||
|
152
docs/ste.txt
Normal file
152
docs/ste.txt
Normal file
@ -0,0 +1,152 @@
|
||||
|
||||
Shadow / Hilight description
|
||||
Version 0.1 (03/06/01)
|
||||
|
||||
by Charles MacDonald
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Unpublished work Copyright 2001 Charles MacDonald
|
||||
|
||||
|
||||
Table of contents
|
||||
|
||||
1.) Introduction
|
||||
2.) Color generation
|
||||
3.) Backgrounds
|
||||
4.) Sprites
|
||||
5.) Overscan / border area
|
||||
6.) Miscellaneous
|
||||
7.) Games that use shadow / hilight mode
|
||||
8.) Disclaimer
|
||||
|
||||
|
||||
1.) Introduction
|
||||
|
||||
The shadow / hilight feature has never been properly documented, so here's
|
||||
my attempt at doing just that.
|
||||
|
||||
I'd like to thank Flavio Morsoletto for sharing results from his
|
||||
shadow / hilight tests.
|
||||
|
||||
2.) Color generation
|
||||
|
||||
As the VDP draws each pixel of the display, it uses the raw pattern data
|
||||
and palette values to select an entry from CRAM, which is used to
|
||||
create red, green, and blue values that define the color of the current
|
||||
pixel being drawn.
|
||||
|
||||
In shadow / hilight mode, the VDP can do two things to the resulting pixel
|
||||
color, either divide it's intensity (brightness) in half, or double it.
|
||||
This is based on two factors, the priority level of the pixel, and the
|
||||
values of the raw pattern and palette data.
|
||||
|
||||
In terms of how the colors are actually generated, imagine that each 3-bit
|
||||
color value from CRAM is scaled up to fit a 0 to 63 range. Half intensity
|
||||
colors would would range from 0 to 31, normal intensity colors would
|
||||
range from 0 to 63, and double intensity colors would range from 32 to 63.
|
||||
|
||||
3.) Backgrounds
|
||||
|
||||
Low priority background tiles are shown at half intensity, high priority
|
||||
background tiles are shown at normal intensity.
|
||||
|
||||
When the VDP renders high priority tiles, it does not take transparent
|
||||
pixels into account. Instead, any underlying pixels (either from the
|
||||
background, sprites, or backdrop) will be shown at normal intensity.
|
||||
|
||||
For example, if you had a completely transparent tile on plane B that
|
||||
had it's priority bit set, any pixel from plane A or the sprite layer
|
||||
that fell within the tile's 8x8 pixel area would be shown at normal
|
||||
intensity.
|
||||
|
||||
4.) Sprites
|
||||
|
||||
Low priority sprites are shown at half intensity, high priority sprites
|
||||
are shown at normal intensity. The priority values do not affect the
|
||||
intensity of any overlapping sprites.
|
||||
|
||||
Any high-priority background tile will force a low-priority sprite to
|
||||
be shown at normal intensity.
|
||||
|
||||
I'm going to call any sprite pixel that uses color 3Eh a hilight
|
||||
operator, and any sprite pixel that uses color 3Fh a shadow operator.
|
||||
Such pixels are not drawn by the VDP, but instead are treated as
|
||||
transparent.
|
||||
|
||||
A shadow operator forces the underlying background or backdrop pixel
|
||||
to be shown at half intensity, regardless of the pixel's priority.
|
||||
|
||||
A hilight operator forces the underlying background or backdrop pixel
|
||||
to be shown at normal intensity if it is currently at half intensity,
|
||||
or at double intensity if it is currently at normal intensity.
|
||||
|
||||
Operator pixels do not affect other sprites. In the case of operator
|
||||
pixels overlapping, the first sprite in the sprite list is the one that
|
||||
defines how the underlying background / backdrop pixel is modified.
|
||||
|
||||
5.) Overscan / border area
|
||||
|
||||
The backdrop is the entire display area (usually 256x224 pixels), which is
|
||||
filled with the color value selected in VDP register #7. The background
|
||||
layers and sprites are overlaid on top of the backdrop, so that any pixel
|
||||
where no background or sprite pixels exist will show the backdrop color.
|
||||
|
||||
Overscan is the area outside of the physical display. You can see it if
|
||||
you adjust the vertical or horizontal hold of a monitor to see past the
|
||||
top/bottom or left/right edges of the screen.
|
||||
|
||||
When shadow / hilight mode is enabled, the overscan area is always
|
||||
displayed at half intensity. The backdrop is also shown at half intensity,
|
||||
but that can be modified by overlaying background tiles or sprites.
|
||||
(either by priority, or by operator pixels)
|
||||
|
||||
If the display is blanked (bit 6 of VDP register #1) or the leftmost
|
||||
column is blanked (bit 5 of VDP register #0), the portion of the display
|
||||
in question has the same properties as the overscan area. (meaning
|
||||
sprites and background tiles cannot affect it's intensity, it is
|
||||
always fixed to half intensity)
|
||||
|
||||
6.) Miscellaneous
|
||||
|
||||
There is a bug in the way sprite pixel colors are processed by the VDP.
|
||||
Color 0Eh of palettes 00-02h is always displayed at normal intensity,
|
||||
regardless of the priority level of the sprite.
|
||||
|
||||
The contents of CRAM for colors 3Eh and 3Fh do not affect the shadow or
|
||||
hilight effect. Though I've noticed many games set one or more of the
|
||||
RGB values for either entry to maximum, like 0EEEh or 0E0Eh.
|
||||
|
||||
For those of you who want some statistics, the Genesis VDP can display 61
|
||||
of 512 colors normally, and 183 of 1536 colors in shadow / hilight mode.
|
||||
That doesn't include duplicate colors, which may or may not exist.
|
||||
|
||||
7.) Games that use shadow / hilight mode
|
||||
|
||||
- Adventures of Batman & Robin
|
||||
- Ecco 2 : The Tides of Time
|
||||
- Gauntlet IV
|
||||
- Mega Turrican
|
||||
- Mortal Kombat
|
||||
- Shinobi III
|
||||
- Skeleton Krew
|
||||
- Sonic 2
|
||||
- Sonic 3, Sonic & Knuckles
|
||||
- Sonic 3D Blast
|
||||
- Space Harrier II
|
||||
- Sub Terrania
|
||||
- Red Zone
|
||||
- Ranger-X
|
||||
|
||||
8.) Disclaimer
|
||||
|
||||
If you use any information from this document, please credit me
|
||||
(Charles MacDonald) and optionally provide a link to my webpage
|
||||
(http://cgfm2.emuviews.com/) so interested parties can access it.
|
||||
|
||||
The credit text should be present in the accompanying documentation of
|
||||
whatever project which used the information, or even in the program
|
||||
itself (e.g. an about box)
|
||||
|
||||
Regarding distribution, you cannot put this document on another
|
||||
website, nor link directly to it.
|
||||
|
79
docs/todo.txt
Normal file
79
docs/todo.txt
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
Here are some technical details about things that need to be fixed or
|
||||
added to Genesis Plus.
|
||||
|
||||
Missing features:
|
||||
|
||||
- Support for 6-button controllers
|
||||
- SRAM management
|
||||
- Game Genie / PAR patch codes
|
||||
|
||||
The VDP code could use a lot of cleaning up.
|
||||
|
||||
The rendering code is missing a few bits:
|
||||
|
||||
- Sprite collision
|
||||
- Window bug
|
||||
|
||||
I think the "C" 68000 emulator either has some bugs or I'm not using it
|
||||
correctly. Older DOS-only versions used Turbo68K, which had ran games
|
||||
much better, especially with regards to interrupt handling.
|
||||
|
||||
Things that need to be fixed:
|
||||
|
||||
- Raster garbage on third road in Thunder Blade.
|
||||
|
||||
- Added country codes for Dragon Slayer, but game locks up after
|
||||
passing country check.
|
||||
|
||||
- No inputs in Samurai Shodown.
|
||||
(This game doesn't initialize the port direction registers, at least not
|
||||
directly. Emulation bug or problem with the game?)
|
||||
|
||||
- Palette and raster problems in Mortal Kombat.
|
||||
|
||||
- Bad raster effects and VRAM corruption in Super Skidmarks.
|
||||
(Needs PAL timing)
|
||||
|
||||
- Palette problems in Sonic 2 title screen.
|
||||
|
||||
- Masked half of Sonic sprite visible on Sonic title screen.
|
||||
|
||||
- Sprite masking doesn't work in Micro Machines subscreen.
|
||||
|
||||
- Music has slow tempo in Batman & Robin. (doesn't seem to be a problem
|
||||
with the YM2612 timers - Wonderboy 3 is normal)
|
||||
|
||||
- Music has jerky playback in Sonic 2, 3, 3D Blast. If you run the Z80
|
||||
emulation for one scanline after requesting an interrupt, it runs fine.
|
||||
|
||||
- DAC and PSG output are too loud, both are divided by two for now
|
||||
(though the PSG should be a bit quieter and the DAC a bit louder)
|
||||
|
||||
- Undead Line locks after selecting a stage, also the Z80 sound halts
|
||||
after the first note is played.
|
||||
|
||||
This game single steps the Z80 with the following code:
|
||||
|
||||
MOVEM.L D0,-(A7) ; 009C7C 48 E7 80 00
|
||||
ORI #$0200,SR ; 009C80 00 7C 02 00
|
||||
; Get control of the Z-bus
|
||||
MOVE.W #$0100,$00A11100 ; 009C84 33 FC 01 00 00 A1 11 00
|
||||
BTST #$00,$00A11100 ; 009C8C 08 39 00 00 00 A1 11 00
|
||||
BNE.S *-$08 [00009C8C] ; 009C94 66 F6
|
||||
; Check driver status byte. If zero, release bus and exit.
|
||||
TST.B $00A00008 ; 009C96 4A 39 00 A0 00 08
|
||||
BEQ *+$0016 [00009CB2] ; 009C9C 67 00 00 14
|
||||
; Release bus and wait for Z80 to resume control. Then restart the loop
|
||||
; and immediately get the bus back again, assuming the Z80 ran at least
|
||||
; one instruction in the meantime.
|
||||
CLR.W $00A11100 ; 009CA0 42 79 00 A1 11 00
|
||||
BTST #$00,$00A11100 ; 009CA6 08 39 00 00 00 A1 11 00
|
||||
BEQ.S *-$08 [00009CA6] ; 009CAE 67 F6
|
||||
BRA.S *-$2C [00009C84] ; 009CB0 60 D2
|
||||
; Release bus and exit.
|
||||
CLR.W $00A11100 ; 009CB2 42 79 00 A1 11 00
|
||||
ANDI #$FDFF,SR ; 009CB8 02 7C FD FF
|
||||
MOVEM.L (A7)+,D0 ; 009CBC 4C DF 00 01
|
||||
RTS ; 009CC0 4E 75
|
||||
|
26
docs/ym2612.txt
Normal file
26
docs/ym2612.txt
Normal file
@ -0,0 +1,26 @@
|
||||
Here's the format of the YM2612 test register ($21), as best as I can
|
||||
tell:
|
||||
|
||||
bit 7 - If bit 6 set, select 0=LSB, 1=MSB of serial data
|
||||
bit 6 - If set, reading status returns serial data LSB or MSB instead of
|
||||
status flags
|
||||
bit 5 - If set, only the attack phase and possibly decay occur, there is
|
||||
no sustain o release. It sounds like each channel was keyed-on rapidly.
|
||||
When the bit is cleared, the channels resume their original position
|
||||
within the envelope so this bit doesn't have any lasting change on
|
||||
them.
|
||||
bit 4 - Data sent to DAC is inverted - this is *really* loud, so turn
|
||||
down the volume before using this bit. ;)
|
||||
bit 3 - Audio output is muted, (the PSG still works of course) bits 4,5
|
||||
will make sound faintly audible when set in conjunction.
|
||||
bit 2 - Timer A and B run 24 times faster.
|
||||
bits 1,0 - No effect.
|
||||
|
||||
Bits 7, 6 allow you to read the serial data sent from the YM2612 to the
|
||||
DAC. (the other chip, YM3012 - not the DAC at $2A/$2B) I'm unsure of the
|
||||
exact format, it's probably similar to the YM2151. Bit 4 inverts the
|
||||
data sent to the DAC, but not the data read from the status register.
|
||||
Compared to the YM2151 test register documented in MAME, the last 3 bits
|
||||
may have something to do with the LFO. And I'm also not entirely sure
|
||||
about the MSB/LSB order for bit 6. Other than that the two work in a
|
||||
mostly identical way.
|
Loading…
Reference in New Issue
Block a user