TI-NESulator SVN reimport
This commit is contained in:
commit
3f4b4990ea
105
doc/Changements.txt
Executable file
105
doc/Changements.txt
Executable file
@ -0,0 +1,105 @@
|
||||
05/10/2007 V0.30 part 2 ... In progress ...
|
||||
- Start rewrite of mapper manager. The goal, like for plugin manager, is
|
||||
to allow in the future to have plugins or mapper in external libraries.
|
||||
- New sound layer using Allegro. Not really accurate, but more portable.
|
||||
A lot of work has to be done on this (especialy because the actual sound
|
||||
is really bad.)
|
||||
|
||||
03/05/2007 V0.30 part 1
|
||||
- Started the process of PPU total rewrite.
|
||||
- Bg seem to draw fine, sprite is under the way
|
||||
- Add new test rom
|
||||
- Blargg sprite_ram test sucessfully ^^
|
||||
- Correct a lot of bug in implementation of a lot of things.
|
||||
- Try to make it accurate as much as possible...
|
||||
- All Blargg PPU test pass with success (in fact only timing is not good,
|
||||
but it's enought good to let Battletoad work correctly... Maybe it's
|
||||
sprite0 related)
|
||||
|
||||
03/04/2007 V0.29
|
||||
- Totaly new memory manager
|
||||
- Simple sound support (only on UNIX, but maybe Windows & DOS can support
|
||||
it)
|
||||
- New plugin manager (a gamegenie plugin like is under development)
|
||||
- New mapper manager
|
||||
- Large bug correction on mappers (MMC3 now behave correclty)
|
||||
- Large bug correction on larges things (like Signal handler now exit
|
||||
correctly if a signal occure when in signal)
|
||||
- Output now much simpler & readable
|
||||
- New cart opening & internal strictures
|
||||
- A very good speed boost with the new memory manager (it's incredible,
|
||||
without speed limitation I can now go near 300/350fps!)
|
||||
- Large part of code reorganisation (needed for the new memory manager and
|
||||
plugin manager)
|
||||
- And an incredible number of modification/bug correction and more and
|
||||
more...
|
||||
- Switch to SVN source control
|
||||
- New command line parser (now it no more a stupid command line parser)
|
||||
- Palette is no more externalized. (removing some path bad behaviour with
|
||||
Mac/unix/Windows version)
|
||||
- Corrections on paddle emulation, now should work near perfect.
|
||||
|
||||
21/02/2007 V0.28
|
||||
- Internal support for mapper #65 (Irem h3001) but not actually active.
|
||||
- Some new debug options
|
||||
|
||||
19/02/2007 V0.27 Internal release
|
||||
- Correction of a blocking bug in the memory module.
|
||||
- The mapper MMC3 now work at nearly 99%. Only IRQ emulation is not as
|
||||
good as I want..
|
||||
- Bug correction on 8x16 sprite support
|
||||
- Now the crashdump generate a file instead of displaying on screen.
|
||||
- The crashdump is more complete
|
||||
|
||||
21/10/2004 V0.26
|
||||
- J'ai rien changé de plus mais now fullspeed !! (ou presque, c'est incompréhensible)
|
||||
- MMC3 en voie de finalisation (reste a débugguer)
|
||||
- Inteception des erreurs du systemes pour l'aide au crash report (cf LisezMoi.txt)
|
||||
- Changement dans la gestion de la mémoire (qq bugs on du donc se glisser :/ )
|
||||
|
||||
19/10/2004 V0.25
|
||||
- Le MMC1 est fonctionel a 99% (manque juste le support des cartouche de 1024Ko)
|
||||
- Support des sprites 8x16 OK
|
||||
- Support de la couleur et des Attribute Tables fonctionnel a 100%
|
||||
- Changement dans l'affichage des sprites (1 passe au lieu de deux)
|
||||
- Un peu plus lent :'(
|
||||
- Version MacOS X
|
||||
- Reorganisation du code sources (pour eviter le garbage lié au différentes versions)
|
||||
- Derniere version avec le code actuelle du PPU (le recodage va commencer)
|
||||
- Toujours l'erreur dans SMB1 :| (me demande si le fichier a pas été abimé) (non il est nickel)
|
||||
- amélioration du support des miroirs
|
||||
- Gestion (et sauvegarde automatique) des jeux a sauvegarde par batterie !! (zelda1, zelda2 fonctionnent !)
|
||||
- Support du mapper AOROM (bonne partie des jeux RARE dont BattleToad)
|
||||
|
||||
12/10/2004 V0.2 allegé(oui oui) nommé "Blocks.nes edition"
|
||||
- Le support du PPU a été amélioré (Sprite0 detect "perfect" pour nestress et ajout du sprite limiter bit)
|
||||
- Le nouveau PPU a été inséré dans le code 68k
|
||||
- /slap nerick pour essayer de faire avancer la date de 2042 !!
|
||||
- et d'autre bricoles que j'ai pu oublier
|
||||
|
||||
13/07/2004 V0.2 (Et oui plus d'1 an apres !!)
|
||||
- Le scrolling est near perfect :)
|
||||
- Support de la couleur #love#
|
||||
- MMC1 fonctionnel a 90% (manque juste la gestion de la VROM, mais bon MM2 l'utilise pas ^^)
|
||||
- Quelque nouvelles fonctionnalitées, cf lisez moi (affichage des name tables, palette, déplacement de l'affichage du fps)
|
||||
- Un (plus ?) nouveau bug (on ne peut plus jouer a smb1 :'( )
|
||||
|
||||
23/05/2003 V0.1 Prealpha
|
||||
- Nouveau mapper supporté ! et d'autres en préparations :)
|
||||
- La version distribué est dorenavent une version Release plus en Debug
|
||||
|
||||
22/05/2003 V0.1 Prealpha - Interne uniquement
|
||||
- Nouvelle implémentation du PPU, devrait etre plus proche de l'original
|
||||
et il est un peu plus rapide. (2 FPS de gagné sur mon P233 :) )
|
||||
- Le scrolling marche :D (enfin presque pbm de timing ?)
|
||||
- Le joystick est la :D on peu jouer maintenant :D
|
||||
|
||||
21/05/2003 V0.0 prealpha release 2
|
||||
- Maintenant le FPS et IPS sont affiché.
|
||||
|
||||
19/05/2003 v0.0 prealpha
|
||||
- Premiere version public, ne sert que de démonstration.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
$Id: Changements.txt 29 2007-04-03 14:34:02Z mtrapier $
|
||||
--------------------------------------------------------------------------------
|
||||
127
doc/Changes.txt
Executable file
127
doc/Changes.txt
Executable file
@ -0,0 +1,127 @@
|
||||
05/10/2007 V0.30 part 2 ... In progress ...
|
||||
- Start rewrite of mapper manager. The goal, like for plugin manager, is
|
||||
to allow in the future to have plugins or mapper in external libraries.
|
||||
- New sound layer using Allegro. Not really accurate, but more portable.
|
||||
A lot of work has to be done on this (especialy because the actual sound
|
||||
is really bad.)
|
||||
- Started a new source organisation. Should be the good one this time !
|
||||
25/10/2007:
|
||||
- Savestate now work correctly (It was not loaded at the right time...)
|
||||
- Mapper manager seems to work correctly ok
|
||||
- [MACOSX] Buils options are better now
|
||||
|
||||
|
||||
- [TODO] Remerge old PPU debug utilities in real plugin form
|
||||
- [TODO] Change the make util. Maybe cmake ?
|
||||
- [TODO] Remerge all mappers with the new manager
|
||||
- [TODO] Rewrite UNIX Makefile for support new src organization.
|
||||
|
||||
03/05/2007 V0.30 part 1
|
||||
- Started the process of PPU total rewrite.
|
||||
- Bg seem to draw fine, sprite is under the way
|
||||
- Add new test rom
|
||||
- Blargg sprite_ram test sucessfully ^^
|
||||
- Correct a lot of bug in implementation of a lot of things.
|
||||
- Try to make it accurate as much as possible...
|
||||
- All Blargg PPU test pass with success (in fact only timing is not good,
|
||||
but it's enought good to let Battletoad work correctly... Maybe it's
|
||||
sprite0 related)
|
||||
|
||||
03/04/2007 V0.29
|
||||
- Totaly new memory manager
|
||||
- Simple sound support (only on UNIX, but maybe Windows & DOS can support
|
||||
it)
|
||||
- New plugin manager (a gamegenie plugin like is under development)
|
||||
- New mapper manager
|
||||
- Large bug correction on mappers (MMC3 now behave correclty)
|
||||
- Large bug correction on larges things (like Signal handler now exit
|
||||
correctly if a signal occure when in signal)
|
||||
- Output now much simpler & readable
|
||||
- New cart opening & internal strictures
|
||||
- A very good speed boost with the new memory manager (it's incredible,
|
||||
without speed limitation I can now go near 300/350fps!)
|
||||
- Large part of code reorganisation (needed for the new memory manager and
|
||||
plugin manager)
|
||||
- And an incredible number of modification/bug correction and more and
|
||||
more...
|
||||
- Switch to SVN source control
|
||||
- New command line parser (now it no more a stupid command line parser)
|
||||
- Palette is no more externalized. (removing some path bad behaviour with
|
||||
Mac/unix/Windows version)
|
||||
- Corrections on paddle emulation, now should work near perfect.
|
||||
|
||||
02/21/2007 V0.28
|
||||
- Internal support for mapper #65 (Irem h3001) but not actually active.
|
||||
- Some new debug options
|
||||
|
||||
02/19/2007 V0.27 Internal release
|
||||
- Correction of a blocking bug in the memory module.
|
||||
- The mapper MMC3 now work at nearly 99%. Only IRQ emulation is not as
|
||||
good as I want..
|
||||
- Bug correction on 8x16 sprite support
|
||||
- Now the crashdump generate a file instead of displaying on screen.
|
||||
- The crashdump is more complete
|
||||
|
||||
21/10/2004 V0.26
|
||||
- I've changed nothing, but now it's really fullspeed ! I can't understand
|
||||
why - MMC3 is nearly finished (need debugging)
|
||||
- NEW - Signal interception for making bug reports. Don't hesitate to copy
|
||||
paste the whole thing and mail it to me
|
||||
- Change on memory management.
|
||||
|
||||
19/10/2004 V0.25
|
||||
- MMC1 is functional at 99% (no support for 1024Kb cart, but I can't find
|
||||
anyone..)
|
||||
- 8x16 sprites are now OK
|
||||
- Attribute tables, and color is now fully functional
|
||||
- No more two pass on sprite display (speed improvement)
|
||||
- A bit more slow :(
|
||||
- NEW - MacOS X version !
|
||||
- Source code reorganisation
|
||||
- May be the lastest version of the actual PPU source code before total
|
||||
rewriting
|
||||
- SMB1 support is always broken.. I can't understand why..
|
||||
- Mirrors mode improved
|
||||
- NEW - Save Ram support added !
|
||||
- AOROM mappers added ! (nearly all RARE game) but timings are not good
|
||||
so..
|
||||
|
||||
12/10/2004 V0.2 allegé(oui oui) nommé "Blocks.nes edition"
|
||||
- Le support du PPU a été amélioré (Sprite0 detect "perfect" pour nestress
|
||||
et ajout du sprite limiter bit)
|
||||
- Le nouveau PPU a été inséré dans le code 68k
|
||||
- /slap nerick pour essayer de faire avancer la date de 2042 !!
|
||||
- et d'autre bricoles que j'ai pu oublier
|
||||
|
||||
13/07/2004 V0.2 (Et oui plus d'1 an apres !!)
|
||||
- Le scrolling est near perfect :)
|
||||
- Support de la couleur #love#
|
||||
- MMC1 fonctionnel a 90% (manque juste la gestion de la VROM, mais bon MM2
|
||||
l'utilise pas ^^)
|
||||
- Quelque nouvelles fonctionnalitées, cf lisez moi (affichage des name
|
||||
tables, palette, déplacement de l'affichage du fps)
|
||||
- Un (plus ?) nouveau bug (on ne peut plus jouer a smb1 :'( )
|
||||
|
||||
23/05/2003 V0.1 Prealpha
|
||||
|
||||
- Nouveau mapper supporté ! et d'autres en préparations :)
|
||||
- La version distribué est dorenavent une version Release plus en Debug
|
||||
|
||||
22/05/2003 V0.1 Prealpha - Interne uniquement
|
||||
|
||||
- Nouvelle implémentation du PPU, devrait etre plus proche de l'original
|
||||
et il est un peu plus rapide. (2 FPS de gagné sur mon P233 :) )
|
||||
- Le scrolling marche :D (enfin presque pbm de timing ?)
|
||||
- Le joystick est la :D on peu jouer maintenant :D
|
||||
|
||||
21/05/2003 V0.0 prealpha release 2
|
||||
|
||||
- Maintenant le FPS et IPS sont affiché.
|
||||
|
||||
19/05/2003 V0.0 prealpha
|
||||
|
||||
- Premiere version public, ne sert que de dŽmonstration.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
$Id: Changes.txt 51 2007-05-22 16:33:04Z mtrapier $
|
||||
--------------------------------------------------------------------------------
|
||||
233
doc/LisezMoi.txt
Executable file
233
doc/LisezMoi.txt
Executable file
@ -0,0 +1,233 @@
|
||||
<---------------------------------------------------------------------------------->
|
||||
TI-NESulator
|
||||
Version 0.26 beta
|
||||
|
||||
Par Manoël TRAPIER aka Godzil
|
||||
godzil at godzil point net
|
||||
|
||||
1 -> #include <disclamer.h>
|
||||
|
||||
L'utilisation de se logiciel se fait a vos risque et périls. Il s'agit d'une pars
|
||||
d'une version non terminée, et en cours de dévellopement, et la diffusion n'a été
|
||||
faite que pour permettre le teste, et la démonstration de se que sera le logiciel
|
||||
final.
|
||||
|
||||
Je ne peut donc être tenu pour responsable en cas de problème lié a l'utilisation
|
||||
ou posession de se logiciel.
|
||||
|
||||
Vous êtes libre de l'utiliser à partir du moment au se logiciel n'a pas été modifié
|
||||
que sa soit de manière binaire, ou par désassemblage. Si vous trouver une version
|
||||
modifié ou fourni avec des fichiers illégaux, veuillez me le faire savoir. Vous
|
||||
trouverez comment me contacter dans la suite de se fichier.
|
||||
|
||||
Vous êtes libre aussi de le distribuer tant que les fichiers contenus dans le
|
||||
paquetage original sont laissé intouché (les fichiers Changements.txt LisezMoi.txt
|
||||
et TINes.exe)
|
||||
|
||||
Information légales :
|
||||
NES, Famicon, Nintendo Entertainment System, Nintendo sont des marques déposé de
|
||||
Nintendo France, Nintendo of america et Nintendo Company, Ltd.
|
||||
Tout les titres et marques apparaisant dans se fichier texte sont la propriété de
|
||||
leurs auteurs respectifs.
|
||||
|
||||
N'oubliez pas aussi que la posession de ROM (Fichier binaire représentant le
|
||||
contenue d'une cartouche) sans en posseder l'originale (la cartouche) est absolument
|
||||
illégale, que vous la gardiez 24 heures ou seulement 30 secondes
|
||||
|
||||
|
||||
2 -> Qu'est-ce que TI-NESulator ?
|
||||
|
||||
TI-NESulator est un émulateur de la console Nintendo Entertainment System
|
||||
(connunément appelé NES) fabriqué par Nintendo au milieu des année 80. L'originalité
|
||||
de cet emulateur est que sa plateforme de fonctionnement principal est les
|
||||
calculatrices TI-89 et TI-92+ de chez Texas Instrument. Ses calculatrices on la
|
||||
particularité de posseder un microprocesseur 68000 de chez motorola, qui est pour
|
||||
se genre de plateforme relativement puissant et programmer un emulateur, meme de
|
||||
NES, sur ses machine est un véritable défit.
|
||||
Tant au niveau matériel que mémoire, la NES et les TI-68k sont completements
|
||||
différents.
|
||||
La NES utilise une version légérement personalisé du microprocesseur 6502
|
||||
fonctionnant a environ 1.7Mhz.
|
||||
|
||||
Vous avez actuellement une version spéciale (comprendre pas faite pour
|
||||
calculatrices TI.) Cette version ne me sert qu'a mettre en oeuvre de nouvelles
|
||||
choses dans la version TI de l'émulateur (notemment a cause d'un gros manque
|
||||
de debuggueur C dans le monde TI.)
|
||||
|
||||
Cette version est et sera toujours plus avancé que la version TI dans le sens ou
|
||||
elle me sert a expérimenter les nouveaux hardware émulé et a finaliser le hardware
|
||||
deja emuler. Une fois fonctionnant d'un maniere convenable sur le portage Windows,
|
||||
les mises a jours sont faites dans la version TI. Mais la version Windows au final
|
||||
contiendra plus de fonctionnalité que la version TI (support des palletes, de la
|
||||
couleur, voir meme le son etc...)
|
||||
|
||||
|
||||
3 -> Utilisation de TI-NESulator
|
||||
|
||||
[A faire.]
|
||||
|
||||
Version courte :
|
||||
|
||||
C:\TINes\>TINES jeux.nes
|
||||
|
||||
Utilisation du Joystick :
|
||||
|
||||
Manette NES Clavier
|
||||
|
||||
HAUT HAUT
|
||||
BAS BAS
|
||||
GAUCHE GAUCHE
|
||||
DROITE DROITE
|
||||
A W
|
||||
B S
|
||||
START ENTER
|
||||
SELECT P
|
||||
|
||||
--------------------------
|
||||
|
||||
Autres touches :
|
||||
R identique a l'apuis du bouton Reset de la console
|
||||
|
||||
|
||||
1-2 A un effet, mais vous risque de pas le voir ;)
|
||||
3 Affiche les Name Tables
|
||||
4 Affiche les Tables d'attributs (de couleur)
|
||||
5 Affiche les palettes
|
||||
6 Affiche la table des sprites
|
||||
|
||||
--------------------------
|
||||
|
||||
Il faut noter aussi qu'afficher ces tables ralenti considérablement la vitesse de
|
||||
l'émulateur
|
||||
|
||||
4 -> Compatibilité
|
||||
|
||||
TI-NESulator version Win32 est normalement compatible avec tous les Windows (95, 98,
|
||||
Me, NT 4, 2000, XP)
|
||||
TI-NESulator version .X (MacOS X) est normalement compatible toutes version de OS X
|
||||
(.1.x .2.x .3.x)
|
||||
L'émulateur émule actuellement avec les mappers :
|
||||
|
||||
- 0 aucun mapper (Super Mario Bros 1, Donkey Kong, ...)
|
||||
|
||||
- 1 MMC1 (a 99%, Megaman 2, Zelda1 & 2, Final Fantasy 1, ...)
|
||||
|
||||
- 2 UNROM (MegaMan, Final fantasy 2, ...)
|
||||
|
||||
- 3 CNROM
|
||||
|
||||
- 4 *NOUVEAU* MMC3 (Super mario Bross 2 & 3, MegaMan 3 à 6, ...)
|
||||
|
||||
- 7 *NOUVEAU* AOROM (Battletoad, ...)
|
||||
|
||||
Les mappers marqué comme *NOUVEAU* sont ceux qui on été ajouté dans la derniere
|
||||
version disponible. Merci de faire un rapport détaillé si vous rencontrer des
|
||||
problèmes avec.
|
||||
|
||||
|
||||
5 -> A faire
|
||||
|
||||
* Optimisation du coeur de l'émulation du CPU de la NES.
|
||||
|
||||
* Son ?
|
||||
|
||||
* Supprimer les printf et les remplacer par l'affichage dans une console (prochaine
|
||||
maj) pour eviter les soucis sur
|
||||
|
||||
- PC: car la console n'est pas forcement ouverte tout le temps
|
||||
- Unix: pour la meme raison
|
||||
- MacOS: aussi (%))
|
||||
- TI: pasqu'on peut pas avoir les deux en meme temps.
|
||||
|
||||
* Recoder le ppu (gestion de l'affichage)
|
||||
|
||||
6 -> Question Réponses
|
||||
|
||||
Q: Pourquoi le jeu xxx ne fonctionne pas ?
|
||||
R: TI-NESulator est actuellement en cours de dévellopement. Beaucoup de jeux ne
|
||||
sont pas supporté.
|
||||
|
||||
Q: Vous dites que certain de jeux ne sont pas supporté, mais si j'essaye xxx, il
|
||||
marche ! Pourquoi ?
|
||||
R: Ceci est du a une des particularité du Hardware de la NES/Famicon. Le hardware
|
||||
de base de la console est assé limité, et la mémoire est aussi tres limité. pour
|
||||
palier à ses limitations, certains jeux utilise ce qu'on appele des Mappers, qui
|
||||
permettent notemment d'avoir des jeux plus gros, et qui sont implémenté dans la
|
||||
cartouche du jeu. Malheureusement supporter tout ses mappers font grossir
|
||||
l'emulateur, et certain on un fonctionnement qui est malheureusement encore
|
||||
inconnu. N'oubliez pas non plus que TI-NESulator est encore en dévellopement.
|
||||
Certain mapper connu ne sont pas encore implémenté.
|
||||
|
||||
Q: Oui puis-je trouver le jeux xxxx ?
|
||||
R: Désolé, je ne donne aucun lien menant, ni aucune ROM de jeux commerciaux.
|
||||
N'oubliez pas que les personnes vous disant que vous avez le droit de ne garder que
|
||||
24h une ROM, vous raconte absolument n'importe quoi. Il est absolument *ILLEGAL* de
|
||||
posseder la ROM d'un jeu que vous ne possedez pas officiellement.
|
||||
|
||||
Q: XXX donne l'air de fonctionner, pourtant il ne reagis pas au touches
|
||||
R: Cet emulateur n'est pas parfait. Certain jeux/demo demandent un fonctionnement
|
||||
tres proche de celui de la console originale, ce que TI-NESulator est encore loin
|
||||
d'arriver a faire
|
||||
|
||||
Q:J'ai des problèmes graphiques avec XXXX
|
||||
R:Cf réponse-ci dessus
|
||||
|
||||
Q: C'est lent :(
|
||||
R: Désolé. Le code est toujours en cours de devellopement. Si vous trouvez trop lent,
|
||||
attendez la prochaine version une surprise vous y attendra peut-etre !
|
||||
|
||||
7 -> En cas de problème
|
||||
|
||||
a) Un jeu indiqué compatible ne fonctionne pas (ie "Mapper non supporté")
|
||||
|
||||
Alors plusieurs possibilité, soit vous avez une autre version du jeu officielle
|
||||
ou non, cela peut changer par exemple le mapper utilisé par le jeux, soit vous
|
||||
avez recuperer un "bad dump", c'est a dire plus simplement une rom foireuse.
|
||||
|
||||
Dans ces deux cas essayez d'en recuperer une autre version.
|
||||
|
||||
b) TI-NESulator à planté !!
|
||||
Si cela arrive regulierement pour le meme jeu et au meme endroit faites moi un
|
||||
crash report avec les information que TI-NESulator vous met dans la console
|
||||
(pour pouvoir la copier tranquillement il faut lancer a partir d'une console
|
||||
et pas faire glisser la rom sur l'executable)
|
||||
|
||||
N'oubliez pas de préciser le nom complet du jeu, la taille du fichier et toutes
|
||||
les infos que vous trouverez pertinante (manipulation a faire etc...)
|
||||
|
||||
|
||||
8 -> Remerciement
|
||||
|
||||
PpHd pour PreOS, et SMA :)
|
||||
TiMad Membre de la XTeam sans lequel XLib existerait pas.
|
||||
nEUrOO Membre de la XTeam sans lequel XLib existerait pas.
|
||||
|
||||
Loopy, Y0Shi,
|
||||
Marrat Fayzullin,
|
||||
et bcp d'autre pour la documentation technique sur la NES
|
||||
|
||||
Ainsi que tout ceux que j'ai pu oublier
|
||||
|
||||
9 -> Litérature
|
||||
|
||||
[A faire.]
|
||||
|
||||
mais lien rapide :
|
||||
|
||||
http://www.nesdev.org
|
||||
|
||||
10 -> Comment me contacter ?
|
||||
s
|
||||
Vous pouvez me contacter grace au forum yAronet
|
||||
http://www.yaronet.com
|
||||
|
||||
Et surtout grace au lien suivant :
|
||||
http://www.yaronet.com/posts.php?sl=&s=2339
|
||||
|
||||
Vous pouvez aussi me joindre par mail en m'écrivant à "godzil chez godzil point net"
|
||||
Vous pouvez aussi essayer de visiter un de mes sites :
|
||||
http://www.godzil.net
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
$Id: LisezMoi.txt 17 2007-03-27 09:25:23Z mtrapier $
|
||||
--------------------------------------------------------------------------------
|
||||
7
doc/TODO.txt
Normal file
7
doc/TODO.txt
Normal file
@ -0,0 +1,7 @@
|
||||
07/10/2007 V0.30 part 2
|
||||
- Remerge old PPU debug utilities in real plugin form [ ]
|
||||
- Change the make util for UNIX. Maybe cmake ? [ ]
|
||||
- Cleanup os/win32 folder [ ]
|
||||
- Thinks about a better svn repository (Maybe a dedibox is a good choice?)
|
||||
[ ]
|
||||
|
||||
112
src/NESCarts.c
Executable file
112
src/NESCarts.c
Executable file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Cart manager - The TI-NESulator Project
|
||||
* NESCart.c
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-02 18:37:41 +0200 (mer, 02 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/NESCarts.c $
|
||||
* $Revision: 50 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/NESCarts.h"
|
||||
#include "include/mappers/manager.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Plateform dependent function */
|
||||
void *LoadFilePtr(char * filename);
|
||||
|
||||
void DumpCartProperties(FILE *out, NesCart * cart)
|
||||
{
|
||||
fprintf(out,
|
||||
"'%s' informations:\n"
|
||||
" Total ROM Size : 0x%06X | Total VROM Size : 0x%06X\n"
|
||||
" Mapper ID : 0x%06X | Mirroring ? : %s\n"
|
||||
" Battery ? : %s | 4 Screen ? : %s \n"
|
||||
" PROMBanks start at : %p |\n"
|
||||
" VROMBanks start at : %p |\n",
|
||||
cart->FileName,
|
||||
cart->PROMSize,
|
||||
cart->VROMSize,
|
||||
cart->MapperID,
|
||||
cart->Flags & iNES_MIRROR? "Horizontal" : "Vertical",
|
||||
cart->Flags & iNES_BATTERY? "Yes": "No ",
|
||||
cart->Flags & iNES_4SCREEN? "Yes": "No ",
|
||||
cart->PROMBanks,
|
||||
cart->VROMBanks);
|
||||
}
|
||||
|
||||
int LoadCart(const char *filename, NesCart * cart)
|
||||
{
|
||||
byte buffer[6];
|
||||
/* Load the cart into memory */
|
||||
cart->File = (byte *)LoadFilePtr(filename);
|
||||
|
||||
|
||||
if (cart->File == -1)
|
||||
return -1;
|
||||
|
||||
sprintf(buffer, "%c%c%c%c", 0x4E, 0x45, 0x53, 0x1A);
|
||||
|
||||
/* Verify that this is a real iNES valid file */
|
||||
if (memcmp(cart->File, buffer, 4))
|
||||
return -1;
|
||||
|
||||
if ((cart->File == NULL) || (cart->File == -1))
|
||||
return -1;
|
||||
|
||||
/* Before go elsewhere, verify that the header is clean !
|
||||
(aka no DiskDude! in it) */
|
||||
if (memcmp(cart->File+7, "DiskDude!", 9) == 0)
|
||||
{
|
||||
printf("\n"
|
||||
"*******************WARNING****************\n"
|
||||
"* The header of this game is not clean *\n"
|
||||
"* (DiskDude! pollution) I will only use *\n"
|
||||
"* basic MapperID (mapper 0-15). This can *\n"
|
||||
"* led to unexpected behavior... *\n"
|
||||
"* *\n"
|
||||
"* PLEASE CLEAN THIS FILE! *\n"
|
||||
"******************WARNING*****************\n\n");
|
||||
/* So this rom file is not clean, we can only rely on the "basic" mapperID */
|
||||
cart->MapperID = cart->File[6]>>4; /* Mapper Type */
|
||||
|
||||
}
|
||||
else
|
||||
{ /* This rom file is clean, we can read the extended MapperID */
|
||||
cart->MapperID = (cart->File[6]>>4)|(cart->File[7]&0xF0); /* Mapper Type */
|
||||
}
|
||||
|
||||
/* Now fill the structure */
|
||||
cart->FileName = filename;
|
||||
|
||||
cart->PROMSize = cart->File[4] * 16 * 1024; /* Size of PROM */
|
||||
cart->VROMSize = cart->File[5] * 8 * 1024; /* Size of VROM */
|
||||
cart->Flags = cart->File[6] & 0x0F;
|
||||
|
||||
/* We don't and we will never support trainer-ed ROM */
|
||||
if (cart->Flags & iNES_TRAINER)
|
||||
{
|
||||
printf("\n"
|
||||
"********************ERROR*****************\n"
|
||||
"* This cart have an embedded trainer. *\n"
|
||||
"* There is NO support for them. *\n"
|
||||
"* Please use a CLEAN dump if you want *\n"
|
||||
"* to play this game. *\n"
|
||||
"********************ERROR*****************\n\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cart->PROMBanks = cart->File + 16; /* Pointer on the first PROM */
|
||||
|
||||
cart->VROMBanks = cart->PROMBanks + cart->PROMSize; /* Pointer on the first VROM */
|
||||
|
||||
DumpCartProperties(stdout, cart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
418
src/apu/SndAlleg.c
Executable file
418
src/apu/SndAlleg.c
Executable file
@ -0,0 +1,418 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** SndUnix.c **/
|
||||
/** **/
|
||||
/** This file contains standard sound generation routines **/
|
||||
/** for Unix using /dev/dsp and /dev/audio. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2002 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "Sound.h"
|
||||
|
||||
#include <allegro.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
//#include <unistd.h>
|
||||
//#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
//#include <sys/ioctl.h>
|
||||
|
||||
#define AUDIO_CONV(A) (128+(A))
|
||||
|
||||
|
||||
AUDIOSTREAM *stream;
|
||||
|
||||
static pthread_t ThreadID;
|
||||
static int SoundFD;
|
||||
static int SoundRate = 0;
|
||||
static int MasterVolume = 64;
|
||||
static int MasterSwitch = (1<<SND_CHANNELS)-1;
|
||||
static int LoopFreq = 25;
|
||||
static int NoiseGen = 1;
|
||||
static int Suspended = 0;
|
||||
|
||||
static struct
|
||||
{
|
||||
int Type; /* Channel type (SND_*) */
|
||||
int Freq; /* Channel frequency (Hz) */
|
||||
int Volume; /* Channel volume (0..255) */
|
||||
|
||||
signed char *Data; /* Wave data (-128..127 each) */
|
||||
int Length; /* Wave length in Data */
|
||||
int Rate; /* Wave playback rate (or 0Hz) */
|
||||
int Pos; /* Wave current position in Data */
|
||||
|
||||
int Count; /* Phase counter */
|
||||
} CH[SND_CHANNELS];
|
||||
|
||||
static void UnixSetWave(int Channel,signed char *Data,int Length,int Rate);
|
||||
static void UnixSetSound(int Channel,int NewType);
|
||||
static void UnixDrum(int Type,int Force);
|
||||
static void UnixSetChannels(int Volume,int Switch);
|
||||
static void UnixSound(int Channel,int NewFreq,int NewVolume);
|
||||
|
||||
static int OpenSoundDevice(int Rate,int Verbose);
|
||||
static void *DSPLoop(void *Arg);
|
||||
|
||||
/** StopSound() **********************************************/
|
||||
/** Temporarily suspend sound. **/
|
||||
/*************************************************************/
|
||||
void StopSound(void) { Suspended=1; }
|
||||
|
||||
/** ResumeSound() ********************************************/
|
||||
/** Resume sound after StopSound(). **/
|
||||
/*************************************************************/
|
||||
void ResumeSound(void) { Suspended=0; }
|
||||
|
||||
/** OpenSoundDevice() ****************************************/
|
||||
/** Open /dev/dsp with a given level of sound quality. **/
|
||||
/** Returns 0 if failed or sound quality (Mode). **/
|
||||
/*************************************************************/
|
||||
static int OpenSoundDevice(int Rate,int Verbose)
|
||||
{
|
||||
voice_start(stream->voice);
|
||||
|
||||
if(Verbose) puts("OK");
|
||||
return(Rate);
|
||||
}
|
||||
|
||||
/** DSPLoop() ************************************************/
|
||||
/** Main loop of the sound server. **/
|
||||
/*************************************************************/
|
||||
static void *DSPLoop(void *Arg)
|
||||
{
|
||||
int Wave[SND_BUFSIZE];
|
||||
unsigned char *Buf;
|
||||
register int J,I,K,L,M,N,L1,L2,A1,A2,V;
|
||||
int FreqCount;
|
||||
|
||||
for(J=0;J<SND_CHANNELS;J++)
|
||||
{
|
||||
CH[J].Type = SND_MELODIC;
|
||||
CH[J].Count = 0;
|
||||
CH[J].Volume = 0;
|
||||
CH[J].Freq = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FreqCount=SoundRate/SND_BUFSIZE;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Buf = get_audio_stream_buffer(stream);
|
||||
|
||||
if (Buf) {
|
||||
FreqCount-=LoopFreq;
|
||||
|
||||
/* If suspending sound... */
|
||||
if(Suspended)
|
||||
{
|
||||
/* Close sound device */
|
||||
while(Suspended) sleep(1);
|
||||
/* Reopen sound device */
|
||||
SoundRate=OpenSoundDevice(SoundRate,0);
|
||||
}
|
||||
|
||||
/* Waveform generator */
|
||||
for(J=0,M=MasterSwitch;M&&(J<SND_CHANNELS);J++,M>>=1)
|
||||
if(CH[J].Freq&&(V=CH[J].Volume)&&(M&1))
|
||||
switch(CH[J].Type)
|
||||
{
|
||||
case SND_NOISE: /* White Noise */
|
||||
/* For high frequencies, recompute volume */
|
||||
if(CH[J].Freq<=SoundRate) K=0x10000*CH[J].Freq/SoundRate;
|
||||
else { V=V*SoundRate/CH[J].Freq;K=0x10000; }
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L1+=K;
|
||||
if(L1&0xFFFF0000)
|
||||
{
|
||||
L1&=0xFFFF;
|
||||
if((NoiseGen<<=1)&0x80000000) NoiseGen^=0x08000001;
|
||||
}
|
||||
Wave[I]+=NoiseGen&1? V:-V;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_WAVE: /* Custom Waveform */
|
||||
/* Waveform data must have correct length! */
|
||||
if(CH[J].Length<=0) break;
|
||||
/* Start counting */
|
||||
K = CH[J].Rate>0? (SoundRate<<15)/CH[J].Freq/CH[J].Rate
|
||||
: (SoundRate<<15)/CH[J].Freq/CH[J].Length;
|
||||
L1 = CH[J].Pos%CH[J].Length;
|
||||
L2 = CH[J].Count;
|
||||
A1 = CH[J].Data[L1]*V;
|
||||
/* If expecting interpolation... */
|
||||
if(L2<K)
|
||||
{
|
||||
/* Compute interpolation parameters */
|
||||
A2 = CH[J].Data[(L1+1)%CH[J].Length]*V;
|
||||
L = (L2>>15)+1;
|
||||
N = ((K-(L2&0x7FFF))>>15)+1;
|
||||
}
|
||||
/* Add waveform to the buffer */
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
if(L2<K)
|
||||
{
|
||||
/* Interpolate linearly */
|
||||
Wave[I]+=A1+L*(A2-A1)/N;
|
||||
/* Next waveform step */
|
||||
L2+=0x8000;
|
||||
/* Next interpolation step */
|
||||
L++;
|
||||
}
|
||||
else
|
||||
{
|
||||
L1 = (L1+L2/K)%CH[J].Length;
|
||||
L2 = (L2%K)+0x8000;
|
||||
A1 = CH[J].Data[L1]*V;
|
||||
Wave[I]+=A1;
|
||||
/* If expecting interpolation... */
|
||||
if(L2<K)
|
||||
{
|
||||
/* Compute interpolation parameters */
|
||||
A2 = CH[J].Data[(L1+1)%CH[J].Length]*V;
|
||||
L = 1;
|
||||
N = ((K-L2)>>15)+1;
|
||||
}
|
||||
}
|
||||
/* End counting */
|
||||
CH[J].Pos = L1;
|
||||
CH[J].Count = L2;
|
||||
break;
|
||||
|
||||
|
||||
case SND_QS_DU0:
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0x2000?(L2&0x8000? V:0):(L2&0x8000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_QS_DU1:
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0x4000?(L2&0x8000? V:0):(L2&0x8000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_QS_DU3:
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0xC000?(L2&0x4000? V:0):(L2&0xC000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_QS_DU2:
|
||||
case SND_MELODIC: /* Melodic Sound */
|
||||
default: /* Default Sound */
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0x8000? (L2&0x8000? V:0):(L2&0x8000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_TRIANGLE: /* Default Sound */
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+= L1&0x2000?V:-V /*(L2&0x8000? V:0):(L2&0x8000? 0:-V)*/;
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mix and convert waveforms */
|
||||
for(J=0;J<SND_BUFSIZE;J++)
|
||||
{
|
||||
I=(Wave[J]*MasterVolume)>>16;
|
||||
I=I<-128? -128:I>127? 127:I;
|
||||
Buf[J]=AUDIO_CONV(I);
|
||||
Wave[J]=0;
|
||||
}
|
||||
free_audio_stream_buffer(stream);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/** InitSound() **********************************************/
|
||||
/** Initialize DSP. Returns Rate on success, 0 otherwise. **/
|
||||
/** Mode is 0 to skip initialization (will be silent). **/
|
||||
/*************************************************************/
|
||||
int InitSound(int Rate,int Verbose)
|
||||
{
|
||||
/* If sound was initialized, kill it */
|
||||
TrashSound();
|
||||
|
||||
/* Silence requested */
|
||||
if(Rate<=0) return(0);
|
||||
|
||||
/* Synthesis rate should be at least 8kHz */
|
||||
if(Rate<8192) Rate=44100;
|
||||
|
||||
/* Initialize things */
|
||||
SoundRate = 0;
|
||||
ThreadID = 0;
|
||||
Suspended = 0;
|
||||
|
||||
/* Set driver functions */
|
||||
SndDriver.SetSound = UnixSetSound;
|
||||
SndDriver.Drum = UnixDrum;
|
||||
SndDriver.SetChannels = UnixSetChannels;
|
||||
SndDriver.Sound = UnixSound;
|
||||
SndDriver.SetWave = UnixSetWave;
|
||||
|
||||
if (install_sound(DIGI_AUTODETECT, MIDI_NONE, "") != 0)
|
||||
{
|
||||
fprintf(stderr, "%s!\n", allegro_error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
stream = play_audio_stream(SND_BUFSIZE, 8, FALSE, Rate, 255, 128);
|
||||
if (!stream) {
|
||||
fprintf(stderr, "Error creating audio stream!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
voice_stop(stream->voice);
|
||||
|
||||
/* Open sound device */
|
||||
if(Verbose) puts("Starting sound server:");
|
||||
if(!(Rate=OpenSoundDevice(Rate,Verbose))) return(0);
|
||||
|
||||
/* Create DSPLoop() thread */
|
||||
if(Verbose) printf(" Creating thread...");
|
||||
if(pthread_create(&ThreadID,0,DSPLoop,0))
|
||||
{ if(Verbose) puts("FAILED");return(0); }
|
||||
|
||||
/* Detach the thread */
|
||||
pthread_detach(ThreadID);
|
||||
|
||||
/* Done */
|
||||
if(Verbose) puts("OK");
|
||||
return(SoundRate=Rate);
|
||||
}
|
||||
|
||||
/** TrashSound() *********************************************/
|
||||
/** Shut DSP down. **/
|
||||
/*************************************************************/
|
||||
void TrashSound(void)
|
||||
{
|
||||
StopSound();
|
||||
printf("%s: Kill thread...\n", __func__);
|
||||
if(ThreadID) pthread_cancel(ThreadID);
|
||||
|
||||
SoundRate = 0;
|
||||
ThreadID = 0;
|
||||
}
|
||||
|
||||
/** UnixSound() **********************************************/
|
||||
/** Generate sound of given frequency (Hz) and volume **/
|
||||
/** (0..255) via given channel. **/
|
||||
/*************************************************************/
|
||||
void UnixSound(int Channel,int NewFreq,int NewVolume)
|
||||
{
|
||||
if((Channel<0)||(Channel>=SND_CHANNELS)) return;
|
||||
if(!NewVolume||!NewFreq) { NewVolume=0;NewFreq=0; }
|
||||
|
||||
CH[Channel].Volume = NewVolume;
|
||||
CH[Channel].Freq = NewFreq;
|
||||
}
|
||||
|
||||
/** UnixSetChannels() ****************************************/
|
||||
/** Set master volume (0..255) and turn channels on/off. **/
|
||||
/** Each bit in Toggle corresponds to a channel (1=on). **/
|
||||
/*************************************************************/
|
||||
void UnixSetChannels(int MVolume,int MSwitch)
|
||||
{
|
||||
/* Set new MasterSwitch value */
|
||||
MasterSwitch = MSwitch;
|
||||
MasterVolume = MVolume;
|
||||
}
|
||||
|
||||
/** UnixSetSound() *******************************************/
|
||||
/** Set sound type (SND_NOISE/SND_MELODIC) for a given **/
|
||||
/** channel. **/
|
||||
/*************************************************************/
|
||||
void UnixSetSound(int Channel,int NewType)
|
||||
{
|
||||
if((Channel<0)||(Channel>=SND_CHANNELS)) return;
|
||||
CH[Channel].Type = NewType;
|
||||
}
|
||||
|
||||
|
||||
/** UnixSetWave() ********************************************/
|
||||
/** Set waveform for a given channel. The channel will be **/
|
||||
/** marked with sound type SND_WAVE. Set Rate=0 if you want **/
|
||||
/** waveform to be an instrument or set it to the waveform **/
|
||||
/** own playback rate. **/
|
||||
/*************************************************************/
|
||||
void UnixSetWave(int Channel,signed char *Data,int Length,int Rate)
|
||||
{
|
||||
if((Channel<0)||(Channel>=SND_CHANNELS)||(Length<=0)) return;
|
||||
|
||||
CH[Channel].Type = SND_WAVE;
|
||||
CH[Channel].Length = Length;
|
||||
CH[Channel].Rate = Rate;
|
||||
CH[Channel].Pos = 0;
|
||||
CH[Channel].Count = 0;
|
||||
CH[Channel].Data = Data;
|
||||
}
|
||||
|
||||
/** UnixDrum() ***********************************************/
|
||||
/** Hit a drum of a given type with given force. **/
|
||||
/*************************************************************/
|
||||
void UnixDrum(int Type,int Force)
|
||||
{
|
||||
/* This function is currently empty */
|
||||
}
|
||||
554
src/apu/SndUnixT.c
Executable file
554
src/apu/SndUnixT.c
Executable file
@ -0,0 +1,554 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** SndUnix.c **/
|
||||
/** **/
|
||||
/** This file contains standard sound generation routines **/
|
||||
/** for Unix using /dev/dsp and /dev/audio. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2002 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#ifdef UNIX
|
||||
|
||||
#include "Sound.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef SUN_AUDIO
|
||||
|
||||
#include <sys/audioio.h>
|
||||
#include <sys/conf.h>
|
||||
#include <stropts.h>
|
||||
|
||||
#define AUDIO_CONV(A) (ULAW[0xFF&(128+(A))])
|
||||
|
||||
static unsigned char ULAW[256] =
|
||||
{
|
||||
31, 31, 31, 32, 32, 32, 32, 33,
|
||||
33, 33, 33, 34, 34, 34, 34, 35,
|
||||
35, 35, 35, 36, 36, 36, 36, 37,
|
||||
37, 37, 37, 38, 38, 38, 38, 39,
|
||||
39, 39, 39, 40, 40, 40, 40, 41,
|
||||
41, 41, 41, 42, 42, 42, 42, 43,
|
||||
43, 43, 43, 44, 44, 44, 44, 45,
|
||||
45, 45, 45, 46, 46, 46, 46, 47,
|
||||
47, 47, 47, 48, 48, 49, 49, 50,
|
||||
50, 51, 51, 52, 52, 53, 53, 54,
|
||||
54, 55, 55, 56, 56, 57, 57, 58,
|
||||
58, 59, 59, 60, 60, 61, 61, 62,
|
||||
62, 63, 63, 64, 65, 66, 67, 68,
|
||||
69, 70, 71, 72, 73, 74, 75, 76,
|
||||
77, 78, 79, 81, 83, 85, 87, 89,
|
||||
91, 93, 95, 99, 103, 107, 111, 119,
|
||||
255, 247, 239, 235, 231, 227, 223, 221,
|
||||
219, 217, 215, 213, 211, 209, 207, 206,
|
||||
205, 204, 203, 202, 201, 200, 199, 198,
|
||||
219, 217, 215, 213, 211, 209, 207, 206,
|
||||
205, 204, 203, 202, 201, 200, 199, 198,
|
||||
197, 196, 195, 194, 193, 192, 191, 191,
|
||||
190, 190, 189, 189, 188, 188, 187, 187,
|
||||
186, 186, 185, 185, 184, 184, 183, 183,
|
||||
182, 182, 181, 181, 180, 180, 179, 179,
|
||||
178, 178, 177, 177, 176, 176, 175, 175,
|
||||
175, 175, 174, 174, 174, 174, 173, 173,
|
||||
173, 173, 172, 172, 172, 172, 171, 171,
|
||||
171, 171, 170, 170, 170, 170, 169, 169,
|
||||
169, 169, 168, 168, 168, 168, 167, 167,
|
||||
167, 167, 166, 166, 166, 166, 165, 165,
|
||||
165, 165, 164, 164, 164, 164, 163, 163
|
||||
};
|
||||
|
||||
#else /* SUN_AUDIO */
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <machine/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#define AUDIO_CONV(A) (128+(A))
|
||||
|
||||
#endif /* SUN_AUDIO */
|
||||
|
||||
static pthread_t ThreadID;
|
||||
static int SoundFD;
|
||||
static int SoundRate = 0;
|
||||
static int MasterVolume = 64;
|
||||
static int MasterSwitch = (1<<SND_CHANNELS)-1;
|
||||
static int LoopFreq = 25;
|
||||
static int NoiseGen = 1;
|
||||
static int Suspended = 0;
|
||||
|
||||
static struct
|
||||
{
|
||||
int Type; /* Channel type (SND_*) */
|
||||
int Freq; /* Channel frequency (Hz) */
|
||||
int Volume; /* Channel volume (0..255) */
|
||||
|
||||
signed char *Data; /* Wave data (-128..127 each) */
|
||||
int Length; /* Wave length in Data */
|
||||
int Rate; /* Wave playback rate (or 0Hz) */
|
||||
int Pos; /* Wave current position in Data */
|
||||
|
||||
int Count; /* Phase counter */
|
||||
} CH[SND_CHANNELS];
|
||||
|
||||
static void UnixSetWave(int Channel,signed char *Data,int Length,int Rate);
|
||||
static void UnixSetSound(int Channel,int NewType);
|
||||
static void UnixDrum(int Type,int Force);
|
||||
static void UnixSetChannels(int Volume,int Switch);
|
||||
static void UnixSound(int Channel,int NewFreq,int NewVolume);
|
||||
|
||||
static int OpenSoundDevice(int Rate,int Verbose);
|
||||
static void *DSPLoop(void *Arg);
|
||||
|
||||
/** StopSound() **********************************************/
|
||||
/** Temporarily suspend sound. **/
|
||||
/*************************************************************/
|
||||
void StopSound(void) { Suspended=1; }
|
||||
|
||||
/** ResumeSound() ********************************************/
|
||||
/** Resume sound after StopSound(). **/
|
||||
/*************************************************************/
|
||||
void ResumeSound(void) { Suspended=0; }
|
||||
|
||||
/** OpenSoundDevice() ****************************************/
|
||||
/** Open /dev/dsp with a given level of sound quality. **/
|
||||
/** Returns 0 if failed or sound quality (Mode). **/
|
||||
/*************************************************************/
|
||||
static int OpenSoundDevice(int Rate,int Verbose)
|
||||
{
|
||||
int I,J,K;
|
||||
|
||||
#ifdef SUN_AUDIO
|
||||
|
||||
if(Verbose) printf(" Opening /dev/audio...");
|
||||
if((SoundFD=open("/dev/audio",O_WRONLY | O_NONBLOCK))==-1)
|
||||
{
|
||||
if(Verbose) puts("FAILED");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Sun's specific initialization should be here...
|
||||
** We assume, that it's set to 8000Hz u-law mono right now.
|
||||
*/
|
||||
|
||||
#else /* SUN_AUDIO */
|
||||
|
||||
/* At first, we need to open /dev/dsp: */
|
||||
if(Verbose) printf(" Opening /dev/dsp...");
|
||||
I=((SoundFD=open("/dev/dsp",O_WRONLY))<0);
|
||||
|
||||
/* Set 8-bit sound */
|
||||
if(!I)
|
||||
{
|
||||
if(Verbose) printf("OK\n Setting mode: 8bit...");
|
||||
J=AFMT_U8;
|
||||
I=(ioctl(SoundFD,SNDCTL_DSP_SETFMT,&J)<0);
|
||||
}
|
||||
|
||||
/* Set mono sound */
|
||||
if(!I)
|
||||
{
|
||||
if(Verbose) printf("mono...");
|
||||
J=0;
|
||||
I=(ioctl(SoundFD,SNDCTL_DSP_STEREO,&J)<0);
|
||||
}
|
||||
|
||||
/* Set sampling rate */
|
||||
if(!I)
|
||||
{
|
||||
if(Verbose) printf("OK\n Setting sampling rate: %dHz...",Rate);
|
||||
I=(ioctl(SoundFD,SNDCTL_DSP_SPEED,&Rate)<0);
|
||||
if(Verbose) printf("(got %dHz)...",Rate);
|
||||
}
|
||||
|
||||
/* Here we set the number of buffers to use */
|
||||
if(!I)
|
||||
{
|
||||
if(Verbose)
|
||||
printf
|
||||
(
|
||||
"OK\n Adjusting buffers: %d buffers %d bytes each...",
|
||||
SND_BUFFERS,1<<SND_BITS
|
||||
);
|
||||
|
||||
/* Set buffer length and number of buffers */
|
||||
J=K=SND_BITS|(SND_BUFFERS<<16);
|
||||
I=(ioctl(SoundFD,SNDCTL_DSP_SETFRAGMENT,&J)<0);
|
||||
|
||||
/* Buffer length as n, not 2^n! */
|
||||
if((J&0xFFFF)<16) J=(J&0xFFFF0000)|(1<<(J&0xFFFF));
|
||||
K=(1<<SND_BITS)|(SND_BUFFERS<<16);
|
||||
|
||||
/* If something went wrong... */
|
||||
if(J!=K)
|
||||
{
|
||||
if((J>>16)<SND_BUFFERS) I=-1;
|
||||
if((J&0xFFFF)!=(1<<SND_BITS)) I=-1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If something failed, fall out */
|
||||
if(I) { if(Verbose) puts("FAILED");return(0); }
|
||||
|
||||
#endif /* SUN_AUDIO */
|
||||
|
||||
if(Verbose) puts("OK");
|
||||
return(Rate);
|
||||
}
|
||||
|
||||
/** DSPLoop() ************************************************/
|
||||
/** Main loop of the sound server. **/
|
||||
/*************************************************************/
|
||||
static void *DSPLoop(void *Arg)
|
||||
{
|
||||
int Wave[SND_BUFSIZE];
|
||||
unsigned char Buf[SND_BUFSIZE];
|
||||
register int J,I,K,L,M,N,L1,L2,A1,A2,V;
|
||||
int FreqCount;
|
||||
|
||||
for(J=0;J<SND_CHANNELS;J++)
|
||||
{
|
||||
CH[J].Type = SND_MELODIC;
|
||||
CH[J].Count = 0;
|
||||
CH[J].Volume = 0;
|
||||
CH[J].Freq = 0;
|
||||
}
|
||||
|
||||
FreqCount=SoundRate/SND_BUFSIZE;
|
||||
for(;;FreqCount-=LoopFreq)
|
||||
{
|
||||
/* If suspending sound... */
|
||||
if(Suspended)
|
||||
{
|
||||
/* Close sound device */
|
||||
#ifndef SUN_AUDIO
|
||||
ioctl(SoundFD,SNDCTL_DSP_RESET);
|
||||
#endif
|
||||
close(SoundFD);
|
||||
/* Suspend execution until Suspended=0 */
|
||||
while(Suspended) sleep(1);
|
||||
/* Reopen sound device */
|
||||
SoundRate=OpenSoundDevice(SoundRate,0);
|
||||
}
|
||||
|
||||
/* Waveform generator */
|
||||
for(J=0,M=MasterSwitch;M&&(J<SND_CHANNELS);J++,M>>=1)
|
||||
if(CH[J].Freq&&(V=CH[J].Volume)&&(M&1))
|
||||
switch(CH[J].Type)
|
||||
{
|
||||
case SND_NOISE: /* White Noise */
|
||||
/* For high frequencies, recompute volume */
|
||||
if(CH[J].Freq<=SoundRate) K=0x10000*CH[J].Freq/SoundRate;
|
||||
else { V=V*SoundRate/CH[J].Freq;K=0x10000; }
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L1+=K;
|
||||
if(L1&0xFFFF0000)
|
||||
{
|
||||
L1&=0xFFFF;
|
||||
if((NoiseGen<<=1)&0x80000000) NoiseGen^=0x08000001;
|
||||
}
|
||||
Wave[I]+=NoiseGen&1? V:-V;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_WAVE: /* Custom Waveform */
|
||||
/* Waveform data must have correct length! */
|
||||
if(CH[J].Length<=0) break;
|
||||
/* Start counting */
|
||||
K = CH[J].Rate>0? (SoundRate<<15)/CH[J].Freq/CH[J].Rate
|
||||
: (SoundRate<<15)/CH[J].Freq/CH[J].Length;
|
||||
L1 = CH[J].Pos%CH[J].Length;
|
||||
L2 = CH[J].Count;
|
||||
A1 = CH[J].Data[L1]*V;
|
||||
/* If expecting interpolation... */
|
||||
if(L2<K)
|
||||
{
|
||||
/* Compute interpolation parameters */
|
||||
A2 = CH[J].Data[(L1+1)%CH[J].Length]*V;
|
||||
L = (L2>>15)+1;
|
||||
N = ((K-(L2&0x7FFF))>>15)+1;
|
||||
}
|
||||
/* Add waveform to the buffer */
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
if(L2<K)
|
||||
{
|
||||
/* Interpolate linearly */
|
||||
Wave[I]+=A1+L*(A2-A1)/N;
|
||||
/* Next waveform step */
|
||||
L2+=0x8000;
|
||||
/* Next interpolation step */
|
||||
L++;
|
||||
}
|
||||
else
|
||||
{
|
||||
L1 = (L1+L2/K)%CH[J].Length;
|
||||
L2 = (L2%K)+0x8000;
|
||||
A1 = CH[J].Data[L1]*V;
|
||||
Wave[I]+=A1;
|
||||
/* If expecting interpolation... */
|
||||
if(L2<K)
|
||||
{
|
||||
/* Compute interpolation parameters */
|
||||
A2 = CH[J].Data[(L1+1)%CH[J].Length]*V;
|
||||
L = 1;
|
||||
N = ((K-L2)>>15)+1;
|
||||
}
|
||||
}
|
||||
/* End counting */
|
||||
CH[J].Pos = L1;
|
||||
CH[J].Count = L2;
|
||||
break;
|
||||
|
||||
|
||||
case SND_QS_DU0:
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0x2000?(L2&0x8000? V:0):(L2&0x8000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_QS_DU1:
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0x4000?(L2&0x8000? V:0):(L2&0x8000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_QS_DU3:
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0xC000?(L2&0x4000? V:0):(L2&0xC000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_QS_DU2:
|
||||
case SND_MELODIC: /* Melodic Sound */
|
||||
default: /* Default Sound */
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+=L1&0x8000? (L2&0x8000? V:0):(L2&0x8000? 0:-V);
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
|
||||
case SND_TRIANGLE: /* Default Sound */
|
||||
/* Do not allow frequencies that are too high */
|
||||
if(CH[J].Freq>=SoundRate/3) break;
|
||||
K=0x10000*CH[J].Freq/SoundRate;
|
||||
L1=CH[J].Count;
|
||||
V<<=7;
|
||||
for(I=0;I<SND_BUFSIZE;I++)
|
||||
{
|
||||
L2=L1+K;
|
||||
Wave[I]+= L1&0x2000?V:-V /*(L2&0x8000? V:0):(L2&0x8000? 0:-V)*/;
|
||||
L1=L2;
|
||||
}
|
||||
CH[J].Count=L1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mix and convert waveforms */
|
||||
for(J=0;J<SND_BUFSIZE;J++)
|
||||
{
|
||||
I=(Wave[J]*MasterVolume)>>16;
|
||||
I=I<-128? -128:I>127? 127:I;
|
||||
Buf[J]=AUDIO_CONV(I);
|
||||
Wave[J]=0;
|
||||
}
|
||||
|
||||
if(SoundFD==-1) sleep(1);
|
||||
else
|
||||
{
|
||||
#ifdef SUN_AUDIO
|
||||
/* Flush output first, don't care about return status. After this
|
||||
** write next buffer of audio data. This method produces a horrible
|
||||
** click on each buffer :( Any ideas, how to fix this?
|
||||
*/
|
||||
ioctl(SoundFD,AUDIO_DRAIN);
|
||||
write(SoundFD,Buf,SND_BUFSIZE);
|
||||
#else
|
||||
/* We'll block here until next DMA buffer becomes free. It happens
|
||||
** once per (1<<SND_BITS)/SoundRate seconds.
|
||||
*/
|
||||
write(SoundFD,Buf,SND_BUFSIZE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/** InitSound() **********************************************/
|
||||
/** Initialize DSP. Returns Rate on success, 0 otherwise. **/
|
||||
/** Mode is 0 to skip initialization (will be silent). **/
|
||||
/*************************************************************/
|
||||
int InitSound(int Rate,int Verbose)
|
||||
{
|
||||
/* If sound was initialized, kill it */
|
||||
TrashSound();
|
||||
|
||||
/* Silence requested */
|
||||
if(Rate<=0) return(0);
|
||||
|
||||
/* Synthesis rate should be at least 8kHz */
|
||||
if(Rate<8192) Rate=44100;
|
||||
|
||||
/* Initialize things */
|
||||
SoundRate = 0;
|
||||
SoundFD = -1;
|
||||
ThreadID = 0;
|
||||
Suspended = 0;
|
||||
|
||||
/* Set driver functions */
|
||||
SndDriver.SetSound = UnixSetSound;
|
||||
SndDriver.Drum = UnixDrum;
|
||||
SndDriver.SetChannels = UnixSetChannels;
|
||||
SndDriver.Sound = UnixSound;
|
||||
SndDriver.SetWave = UnixSetWave;
|
||||
|
||||
/* Open sound device */
|
||||
if(Verbose) puts("Starting sound server:");
|
||||
if(!(Rate=OpenSoundDevice(Rate,Verbose))) return(0);
|
||||
|
||||
/* Create DSPLoop() thread */
|
||||
if(Verbose) printf(" Creating thread...");
|
||||
if(pthread_create(&ThreadID,0,DSPLoop,0))
|
||||
{ if(Verbose) puts("FAILED");return(0); }
|
||||
|
||||
/* Detach the thread */
|
||||
pthread_detach(ThreadID);
|
||||
|
||||
/* Done */
|
||||
if(Verbose) puts("OK");
|
||||
return(SoundRate=Rate);
|
||||
}
|
||||
|
||||
/** TrashSound() *********************************************/
|
||||
/** Shut DSP down. **/
|
||||
/*************************************************************/
|
||||
void TrashSound(void)
|
||||
{
|
||||
StopSound();
|
||||
printf("%s: Kill thread...\n", __func__);
|
||||
if(ThreadID) pthread_cancel(ThreadID);
|
||||
printf("%s: close /dev/xxx ...\n", __func__);
|
||||
if(SoundFD!=-1) close(SoundFD);
|
||||
|
||||
SoundRate = 0;
|
||||
SoundFD = -1;
|
||||
ThreadID = 0;
|
||||
}
|
||||
|
||||
/** UnixSound() **********************************************/
|
||||
/** Generate sound of given frequency (Hz) and volume **/
|
||||
/** (0..255) via given channel. **/
|
||||
/*************************************************************/
|
||||
void UnixSound(int Channel,int NewFreq,int NewVolume)
|
||||
{
|
||||
if((Channel<0)||(Channel>=SND_CHANNELS)) return;
|
||||
if(!NewVolume||!NewFreq) { NewVolume=0;NewFreq=0; }
|
||||
|
||||
CH[Channel].Volume = NewVolume;
|
||||
CH[Channel].Freq = NewFreq;
|
||||
}
|
||||
|
||||
/** UnixSetChannels() ****************************************/
|
||||
/** Set master volume (0..255) and turn channels on/off. **/
|
||||
/** Each bit in Toggle corresponds to a channel (1=on). **/
|
||||
/*************************************************************/
|
||||
void UnixSetChannels(int MVolume,int MSwitch)
|
||||
{
|
||||
/* Set new MasterSwitch value */
|
||||
MasterSwitch = MSwitch;
|
||||
MasterVolume = MVolume;
|
||||
}
|
||||
|
||||
/** UnixSetSound() *******************************************/
|
||||
/** Set sound type (SND_NOISE/SND_MELODIC) for a given **/
|
||||
/** channel. **/
|
||||
/*************************************************************/
|
||||
void UnixSetSound(int Channel,int NewType)
|
||||
{
|
||||
if((Channel<0)||(Channel>=SND_CHANNELS)) return;
|
||||
CH[Channel].Type = NewType;
|
||||
}
|
||||
|
||||
|
||||
/** UnixSetWave() ********************************************/
|
||||
/** Set waveform for a given channel. The channel will be **/
|
||||
/** marked with sound type SND_WAVE. Set Rate=0 if you want **/
|
||||
/** waveform to be an instrument or set it to the waveform **/
|
||||
/** own playback rate. **/
|
||||
/*************************************************************/
|
||||
void UnixSetWave(int Channel,signed char *Data,int Length,int Rate)
|
||||
{
|
||||
if((Channel<0)||(Channel>=SND_CHANNELS)||(Length<=0)) return;
|
||||
|
||||
CH[Channel].Type = SND_WAVE;
|
||||
CH[Channel].Length = Length;
|
||||
CH[Channel].Rate = Rate;
|
||||
CH[Channel].Pos = 0;
|
||||
CH[Channel].Count = 0;
|
||||
CH[Channel].Data = Data;
|
||||
}
|
||||
|
||||
/** UnixDrum() ***********************************************/
|
||||
/** Hit a drum of a given type with given force. **/
|
||||
/*************************************************************/
|
||||
void UnixDrum(int Type,int Force)
|
||||
{
|
||||
/* This function is currently empty */
|
||||
}
|
||||
|
||||
#endif /* UNIX */
|
||||
497
src/apu/Sound.c
Normal file
497
src/apu/Sound.c
Normal file
@ -0,0 +1,497 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** Sound.c **/
|
||||
/** **/
|
||||
/** This file file implements core part of the sound API **/
|
||||
/** and functions needed to log soundtrack into a MIDI **/
|
||||
/** file. See Sound.h for declarations. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2007 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "Sound.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
|
||||
struct SndDriverStruct SndDriver =
|
||||
{
|
||||
(void (*)(int,int))0,
|
||||
(void (*)(int,int))0,
|
||||
(void (*)(int,int))0,
|
||||
(void (*)(int,int,int))0,
|
||||
(void (*)(int,const signed char *,int,int))0,
|
||||
(const signed char *(*)(int))0
|
||||
};
|
||||
|
||||
static const struct { byte Note;word Wheel; } Freqs[4096] =
|
||||
{
|
||||
#include "MIDIFreq.h"
|
||||
};
|
||||
|
||||
static const int Programs[5] =
|
||||
{
|
||||
80, /* SND_MELODIC/SND_RECTANGLE */
|
||||
80, /* SND_TRIANGLE */
|
||||
122, /* SND_NOISE */
|
||||
122, /* SND_PERIODIC */
|
||||
80 /* SND_WAVE */
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
int Type;
|
||||
int Note;
|
||||
int Pitch;
|
||||
int Level;
|
||||
} CH[MIDI_CHANNELS] =
|
||||
{
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 },
|
||||
{ -1,-1,-1,-1 }
|
||||
};
|
||||
|
||||
static const char *LogName = 0;
|
||||
static int Logging = MIDI_OFF;
|
||||
static int TickCount = 0;
|
||||
static int LastMsg = -1;
|
||||
static int DrumOn = 0;
|
||||
static FILE *MIDIOut = 0;
|
||||
|
||||
static void MIDISound(int Channel,int Freq,int Volume);
|
||||
static void MIDISetSound(int Channel,int Type);
|
||||
static void MIDIDrum(int Type,int Force);
|
||||
static void MIDIMessage(byte D0,byte D1,byte D2);
|
||||
static void NoteOn(byte Channel,byte Note,byte Level);
|
||||
static void NoteOff(byte Channel);
|
||||
static void WriteDelta(void);
|
||||
static void WriteTempo(int Freq);
|
||||
|
||||
/** SHIFT() **************************************************/
|
||||
/** Make MIDI channel#10 last, as it is normally used for **/
|
||||
/** percussion instruments only and doesn't sound nice. **/
|
||||
/*************************************************************/
|
||||
#define SHIFT(Ch) (Ch==15? 9:Ch>8? Ch+1:Ch)
|
||||
|
||||
/** Sound() **************************************************/
|
||||
/** Generate sound of given frequency (Hz) and volume **/
|
||||
/** (0..255) via given channel. Setting Freq=0 or Volume=0 **/
|
||||
/** turns sound off. **/
|
||||
/*************************************************************/
|
||||
void Sound(int Channel,int Freq,int Volume)
|
||||
{
|
||||
if(Channel<0) return;
|
||||
Freq = Freq<0? 0:Freq;
|
||||
Volume = Volume<0? 0:Volume>255? 255:Volume;
|
||||
|
||||
/* Call sound driver if present */
|
||||
if(SndDriver.Sound) (*SndDriver.Sound)(Channel,Freq,Volume);
|
||||
|
||||
/* Log sound to MIDI file */
|
||||
MIDISound(Channel,Freq,Volume);
|
||||
}
|
||||
|
||||
/** Drum() ***************************************************/
|
||||
/** Hit a drum of given type with given force (0..255). **/
|
||||
/** MIDI drums can be used by ORing their numbers with **/
|
||||
/** SND_MIDI. **/
|
||||
/*************************************************************/
|
||||
void Drum(int Type,int Force)
|
||||
{
|
||||
Force = Force<0? 0:Force>255? 255:Force;
|
||||
|
||||
if(SndDriver.Drum) (*SndDriver.Drum)(Type,Force);
|
||||
|
||||
/* Log drum to MIDI file */
|
||||
MIDIDrum(Type,Force);
|
||||
}
|
||||
|
||||
/** SetSound() ***********************************************/
|
||||
/** Set sound type at a given channel. MIDI instruments can **/
|
||||
/** be set directly by ORing their numbers with SND_MIDI. **/
|
||||
/*************************************************************/
|
||||
void SetSound(int Channel,int Type)
|
||||
{
|
||||
if(Channel<0) return;
|
||||
|
||||
if(SndDriver.SetSound) (*SndDriver.SetSound)(Channel,Type);
|
||||
|
||||
/* Log instrument change to MIDI file */
|
||||
MIDISetSound(Channel,Type);
|
||||
}
|
||||
|
||||
/** SetChannels() ********************************************/
|
||||
/** Set master volume (0..255) and switch channels on/off. **/
|
||||
/** Each channel N has corresponding bit 2^N in Switch. Set **/
|
||||
/** or reset this bit to turn the channel on or off. **/
|
||||
/*************************************************************/
|
||||
void SetChannels(int Volume,int Switch)
|
||||
{
|
||||
Volume = Volume<0? 0:Volume>255? 255:Volume;
|
||||
|
||||
if(SndDriver.SetChannels) (*SndDriver.SetChannels)(Volume,Switch);
|
||||
}
|
||||
|
||||
/** SetWave() ************************************************/
|
||||
/** Set waveform for a given channel. The channel will be **/
|
||||
/** marked with sound type SND_WAVE. Set Rate=0 if you want **/
|
||||
/** waveform to be an instrument or set it to the waveform **/
|
||||
/** own playback rate. **/
|
||||
/*************************************************************/
|
||||
void SetWave(int Channel,const signed char *Data,int Length,int Rate)
|
||||
{
|
||||
if((Channel<0)||(Length<=0)) return;
|
||||
|
||||
if(SndDriver.SetWave) (*SndDriver.SetWave)(Channel,Data,Length,Rate);
|
||||
|
||||
/* Log instrument change to MIDI file */
|
||||
MIDISetSound(Channel,Rate? -1:SND_MELODIC);
|
||||
}
|
||||
|
||||
/** GetWave() ************************************************/
|
||||
/** Get current read position for the buffer set with the **/
|
||||
/** SetWave() call. Returns 0 if no buffer has been set, or **/
|
||||
/** if there is no playrate set (i.e. wave is instrument). **/
|
||||
/*************************************************************/
|
||||
const signed char *GetWave(int Channel)
|
||||
{
|
||||
return(SndDriver.GetWave? (*SndDriver.GetWave)(Channel):0);
|
||||
}
|
||||
|
||||
/** InitMIDI() ***********************************************/
|
||||
/** Initialize soundtrack logging into MIDI file FileName. **/
|
||||
/** Repeated calls to InitMIDI() will close current MIDI **/
|
||||
/** file and continue logging into a new one. **/
|
||||
/*************************************************************/
|
||||
void InitMIDI(const char *FileName)
|
||||
{
|
||||
int WasLogging;
|
||||
|
||||
/* Must pass a name! */
|
||||
if(!FileName) return;
|
||||
|
||||
/* Memorize logging status */
|
||||
WasLogging=Logging;
|
||||
|
||||
/* If MIDI logging in progress, close current file */
|
||||
if(MIDIOut) TrashMIDI();
|
||||
|
||||
/* Set log file name and ticks/second parameter, no logging yet */
|
||||
LogName = FileName;
|
||||
Logging = MIDI_OFF;
|
||||
LastMsg = -1;
|
||||
TickCount = 0;
|
||||
MIDIOut = 0;
|
||||
DrumOn = 0;
|
||||
|
||||
/* If was logging, restart */
|
||||
if(WasLogging) MIDILogging(MIDI_ON);
|
||||
}
|
||||
|
||||
/** TrashMIDI() **********************************************/
|
||||
/** Finish logging soundtrack and close the MIDI file. **/
|
||||
/*************************************************************/
|
||||
void TrashMIDI(void)
|
||||
{
|
||||
long Length;
|
||||
int J;
|
||||
|
||||
/* If not logging, drop out */
|
||||
if(!MIDIOut) return;
|
||||
/* Turn sound off */
|
||||
for(J=0;J<MIDI_CHANNELS;J++) NoteOff(J);
|
||||
/* End of track */
|
||||
MIDIMessage(0xFF,0x2F,0x00);
|
||||
/* Put track length in file */
|
||||
fseek(MIDIOut,0,SEEK_END);
|
||||
Length=ftell(MIDIOut)-22;
|
||||
fseek(MIDIOut,18,SEEK_SET);
|
||||
fputc((Length>>24)&0xFF,MIDIOut);
|
||||
fputc((Length>>16)&0xFF,MIDIOut);
|
||||
fputc((Length>>8)&0xFF,MIDIOut);
|
||||
fputc(Length&0xFF,MIDIOut);
|
||||
|
||||
/* Done logging */
|
||||
fclose(MIDIOut);
|
||||
Logging = MIDI_OFF;
|
||||
LastMsg = -1;
|
||||
TickCount = 0;
|
||||
MIDIOut = 0;
|
||||
}
|
||||
|
||||
/** MIDILogging() ********************************************/
|
||||
/** Turn soundtrack logging on/off and return its current **/
|
||||
/** status. Possible values of Switch are MIDI_OFF (turn **/
|
||||
/** logging off), MIDI_ON (turn logging on), MIDI_TOGGLE **/
|
||||
/** (toggle logging), and MIDI_QUERY (just return current **/
|
||||
/** state of logging). **/
|
||||
/*************************************************************/
|
||||
int MIDILogging(int Switch)
|
||||
{
|
||||
static const char MThd[] = "MThd\0\0\0\006\0\0\0\1";
|
||||
/* ID DataLen Fmt Trks */
|
||||
static const char MTrk[] = "MTrk\0\0\0\0";
|
||||
/* ID TrkLen */
|
||||
int J,I;
|
||||
|
||||
/* Toggle logging if requested */
|
||||
if(Switch==MIDI_TOGGLE) Switch=!Logging;
|
||||
|
||||
if((Switch==MIDI_ON)||(Switch==MIDI_OFF))
|
||||
if(Switch^Logging)
|
||||
{
|
||||
/* When turning logging off, silence all channels */
|
||||
if(!Switch&&MIDIOut)
|
||||
for(J=0;J<MIDI_CHANNELS;J++) NoteOff(J);
|
||||
|
||||
/* When turning logging on, open MIDI file */
|
||||
if(Switch&&!MIDIOut&&LogName)
|
||||
{
|
||||
/* No messages have been sent yet */
|
||||
LastMsg=-1;
|
||||
|
||||
/* Clear all storage */
|
||||
for(J=0;J<MIDI_CHANNELS;J++)
|
||||
CH[J].Note=CH[J].Pitch=CH[J].Level=-1;
|
||||
|
||||
/* Open new file and write out the header */
|
||||
MIDIOut=fopen(LogName,"wb");
|
||||
if(!MIDIOut) return(MIDI_OFF);
|
||||
if(fwrite(MThd,1,12,MIDIOut)!=12)
|
||||
{ fclose(MIDIOut);MIDIOut=0;return(MIDI_OFF); }
|
||||
fputc((MIDI_DIVISIONS>>8)&0xFF,MIDIOut);
|
||||
fputc(MIDI_DIVISIONS&0xFF,MIDIOut);
|
||||
if(fwrite(MTrk,1,8,MIDIOut)!=8)
|
||||
{ fclose(MIDIOut);MIDIOut=0;return(MIDI_OFF); }
|
||||
|
||||
/* Write out the tempo */
|
||||
WriteTempo(MIDI_DIVISIONS);
|
||||
}
|
||||
|
||||
/* Turn logging off on failure to open MIDIOut */
|
||||
if(!MIDIOut) Switch=MIDI_OFF;
|
||||
|
||||
/* Assign new switch value */
|
||||
Logging=Switch;
|
||||
|
||||
/* If switching logging on... */
|
||||
if(Switch)
|
||||
{
|
||||
/* Start logging without a pause */
|
||||
TickCount=0;
|
||||
|
||||
/* Write instrument changes */
|
||||
for(J=0;J<MIDI_CHANNELS;J++)
|
||||
if((CH[J].Type>=0)&&(CH[J].Type&0x10000))
|
||||
{
|
||||
I=CH[J].Type&~0x10000;
|
||||
CH[J].Type=-1;
|
||||
MIDISetSound(J,I);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return current logging status */
|
||||
return(Logging);
|
||||
}
|
||||
|
||||
/** MIDITicks() **********************************************/
|
||||
/** Log N 1ms MIDI ticks. **/
|
||||
/*************************************************************/
|
||||
void MIDITicks(int N)
|
||||
{
|
||||
if(Logging&&MIDIOut&&(N>0)) TickCount+=N;
|
||||
}
|
||||
|
||||
/** MIDISound() **********************************************/
|
||||
/** Set sound frequency (Hz) and volume (0..255) for a **/
|
||||
/** given channel. **/
|
||||
/*************************************************************/
|
||||
void MIDISound(int Channel,int Freq,int Volume)
|
||||
{
|
||||
int MIDIVolume,MIDINote,MIDIWheel;
|
||||
|
||||
/* If logging off, file closed, or invalid channel, drop out */
|
||||
if(!Logging||!MIDIOut||(Channel>=MIDI_CHANNELS-1)||(Channel<0)) return;
|
||||
/* Frequency must be in range */
|
||||
if((Freq<MIDI_MINFREQ)||(Freq>MIDI_MAXFREQ)) Freq=0;
|
||||
/* Volume must be in range */
|
||||
if(Volume<0) Volume=0; else if(Volume>255) Volume=255;
|
||||
/* Instrument number must be valid */
|
||||
if(CH[Channel].Type<0) Freq=0;
|
||||
|
||||
if(!Volume||!Freq) NoteOff(Channel);
|
||||
else
|
||||
{
|
||||
/* SND_TRIANGLE is twice quieter than SND_MELODIC */
|
||||
if(CH[Channel].Type==SND_TRIANGLE) Volume=(Volume+1)/2;
|
||||
/* Compute MIDI note parameters */
|
||||
MIDIVolume = (127*Volume+128)/255;
|
||||
MIDINote = Freqs[Freq/3].Note;
|
||||
MIDIWheel = Freqs[Freq/3].Wheel;
|
||||
|
||||
/* Play new note */
|
||||
NoteOn(Channel,MIDINote,MIDIVolume);
|
||||
|
||||
/* Change pitch */
|
||||
if(CH[Channel].Pitch!=MIDIWheel)
|
||||
{
|
||||
MIDIMessage(0xE0+SHIFT(Channel),MIDIWheel&0x7F,(MIDIWheel>>7)&0x7F);
|
||||
CH[Channel].Pitch=MIDIWheel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** MIDISetSound() *******************************************/
|
||||
/** Set sound type for a given channel. **/
|
||||
/*************************************************************/
|
||||
void MIDISetSound(int Channel,int Type)
|
||||
{
|
||||
/* Channel must be valid */
|
||||
if((Channel>=MIDI_CHANNELS-1)||(Channel<0)) return;
|
||||
|
||||
/* If instrument changed... */
|
||||
if(CH[Channel].Type!=Type)
|
||||
{
|
||||
/* If logging off or file closed, drop out */
|
||||
if(!Logging||!MIDIOut) CH[Channel].Type=Type|0x10000;
|
||||
else
|
||||
{
|
||||
CH[Channel].Type=Type;
|
||||
if(Type<0) NoteOff(Channel);
|
||||
else
|
||||
{
|
||||
Type=Type&SND_MIDI? (Type&0x7F):Programs[Type%5];
|
||||
MIDIMessage(0xC0+SHIFT(Channel),Type,255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** MIDIDrum() ***********************************************/
|
||||
/** Hit a drum of a given type with given force. **/
|
||||
/*************************************************************/
|
||||
void MIDIDrum(int Type,int Force)
|
||||
{
|
||||
/* If logging off or invalid channel, drop out */
|
||||
if(!Logging||!MIDIOut) return;
|
||||
/* The only non-MIDI drum is a click ("Low Wood Block") */
|
||||
Type=Type&DRM_MIDI? (Type&0x7F):77;
|
||||
/* Release previous drum */
|
||||
if(DrumOn) MIDIMessage(0x89,DrumOn,127);
|
||||
/* Hit next drum */
|
||||
if(Type) MIDIMessage(0x99,Type,(Force&0xFF)/2);
|
||||
DrumOn=Type;
|
||||
}
|
||||
|
||||
/** MIDIMessage() ********************************************/
|
||||
/** Write out a MIDI message. **/
|
||||
/*************************************************************/
|
||||
void MIDIMessage(byte D0,byte D1,byte D2)
|
||||
{
|
||||
/* Write number of ticks that passed */
|
||||
WriteDelta();
|
||||
|
||||
/* Write out the command */
|
||||
if(D0!=LastMsg) { LastMsg=D0;fputc(D0,MIDIOut); }
|
||||
|
||||
/* Write out the arguments */
|
||||
if(D1<128)
|
||||
{
|
||||
fputc(D1,MIDIOut);
|
||||
if(D2<128) fputc(D2,MIDIOut);
|
||||
}
|
||||
}
|
||||
|
||||
/** NoteOn() *************************************************/
|
||||
/** Turn on a note on a given channel. **/
|
||||
/*************************************************************/
|
||||
void NoteOn(byte Channel,byte Note,byte Level)
|
||||
{
|
||||
Note = Note>0x7F? 0x7F:Note;
|
||||
Level = Level>0x7F? 0x7F:Level;
|
||||
|
||||
if((CH[Channel].Note!=Note)||(CH[Channel].Level!=Level))
|
||||
{
|
||||
if(CH[Channel].Note>=0) NoteOff(Channel);
|
||||
MIDIMessage(0x90+SHIFT(Channel),Note,Level);
|
||||
CH[Channel].Note=Note;
|
||||
CH[Channel].Level=Level;
|
||||
}
|
||||
}
|
||||
|
||||
/** NoteOff() ************************************************/
|
||||
/** Turn off a note on a given channel. **/
|
||||
/*************************************************************/
|
||||
void NoteOff(byte Channel)
|
||||
{
|
||||
if(CH[Channel].Note>=0)
|
||||
{
|
||||
MIDIMessage(0x80+SHIFT(Channel),CH[Channel].Note,127);
|
||||
CH[Channel].Note=-1;
|
||||
}
|
||||
}
|
||||
|
||||
/** WriteDelta() *********************************************/
|
||||
/** Write number of ticks since the last MIDI command and **/
|
||||
/** reset the counter. **/
|
||||
/*************************************************************/
|
||||
void WriteDelta(void)
|
||||
{
|
||||
if(TickCount<128) fputc(TickCount,MIDIOut);
|
||||
else
|
||||
{
|
||||
if(TickCount<128*128)
|
||||
{
|
||||
fputc((TickCount>>7)|0x80,MIDIOut);
|
||||
fputc(TickCount&0x7F,MIDIOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
fputc(((TickCount>>14)&0x7F)|0x80,MIDIOut);
|
||||
fputc(((TickCount>>7)&0x7F)|0x80,MIDIOut);
|
||||
fputc(TickCount&0x7F,MIDIOut);
|
||||
}
|
||||
}
|
||||
|
||||
TickCount=0;
|
||||
}
|
||||
|
||||
/** WriteTempo() *********************************************/
|
||||
/** Write out soundtrack tempo (Hz). **/
|
||||
/*************************************************************/
|
||||
void WriteTempo(int Freq)
|
||||
{
|
||||
int J;
|
||||
|
||||
J=500000*MIDI_DIVISIONS*2/Freq;
|
||||
WriteDelta();
|
||||
fputc(0xFF,MIDIOut);
|
||||
fputc(0x51,MIDIOut);
|
||||
fputc(0x03,MIDIOut);
|
||||
fputc((J>>16)&0xFF,MIDIOut);
|
||||
fputc((J>>8)&0xFF,MIDIOut);
|
||||
fputc(J&0xFF,MIDIOut);
|
||||
}
|
||||
837
src/corecpu/Codes.h
Executable file
837
src/corecpu/Codes.h
Executable file
@ -0,0 +1,837 @@
|
||||
/** M6502: portable 6502 emulator ****************************/
|
||||
/** **/
|
||||
/** Codes.h **/
|
||||
/** **/
|
||||
/** This file contains implementation for the main table of **/
|
||||
/** 6502 commands. It is included from 6502.c. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2002 **/
|
||||
/** Alex Krasivsky 1996 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
/*
|
||||
* $LastChangedDate: 2007-05-31 18:01:41 +0200 (jeu, 31 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/Codes.h $
|
||||
* $Revision: 57 $
|
||||
*/
|
||||
|
||||
case 0x10:
|
||||
if (R->P & N_FLAG)
|
||||
R->PC.W++;
|
||||
else
|
||||
{
|
||||
M_JR;
|
||||
} break; /* BPL * REL */
|
||||
|
||||
case 0x30:
|
||||
if (R->P & N_FLAG)
|
||||
{
|
||||
M_JR;
|
||||
}
|
||||
else
|
||||
R->PC.W++;
|
||||
break; /* BMI * REL */
|
||||
|
||||
case 0xD0:
|
||||
if (R->P & Z_FLAG)
|
||||
R->PC.W++;
|
||||
else
|
||||
{
|
||||
M_JR;
|
||||
} break; /* BNE * REL */
|
||||
|
||||
case 0xF0:
|
||||
if (R->P & Z_FLAG)
|
||||
{
|
||||
M_JR;
|
||||
}
|
||||
else
|
||||
R->PC.W++;
|
||||
break; /* BEQ * REL */
|
||||
|
||||
case 0x90:
|
||||
if (R->P & C_FLAG)
|
||||
R->PC.W++;
|
||||
else
|
||||
{
|
||||
M_JR;
|
||||
} break; /* BCC * REL */
|
||||
|
||||
case 0xB0:
|
||||
if (R->P & C_FLAG)
|
||||
{
|
||||
M_JR;
|
||||
}
|
||||
else
|
||||
R->PC.W++;
|
||||
break; /* BCS * REL */
|
||||
|
||||
case 0x50:
|
||||
if (R->P & V_FLAG)
|
||||
R->PC.W++;
|
||||
else
|
||||
{
|
||||
M_JR;
|
||||
} break; /* BVC * REL */
|
||||
|
||||
case 0x70:
|
||||
if (R->P & V_FLAG)
|
||||
{
|
||||
M_JR;
|
||||
}
|
||||
else
|
||||
R->PC.W++;
|
||||
break; /* BVS * REL */
|
||||
|
||||
|
||||
/* RTI */
|
||||
case 0x40:
|
||||
|
||||
M_POP(R->P);
|
||||
R->P |= R_FLAG;
|
||||
M_POP(R->PC.B.l);
|
||||
M_POP(R->PC.B.h);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
/* RTS */
|
||||
case 0x60:
|
||||
|
||||
M_POP(R->PC.B.l);
|
||||
M_POP(R->PC.B.h);
|
||||
R->PC.W++;
|
||||
break;
|
||||
|
||||
|
||||
/* JSR $ssss ABS */
|
||||
case 0x20:
|
||||
|
||||
K.B.l = Op6502(R->PC.W++);
|
||||
|
||||
K.B.h = Op6502(R->PC.W);
|
||||
|
||||
M_PUSH(R->PC.B.h);
|
||||
|
||||
M_PUSH(R->PC.B.l);
|
||||
|
||||
R->PC = K;
|
||||
break;
|
||||
|
||||
|
||||
/* JMP $ssss ABS */
|
||||
case 0x4C:
|
||||
M_LDWORD(K);
|
||||
R->PC = K;
|
||||
break;
|
||||
|
||||
|
||||
/* JMP ($ssss) ABDINDIR */
|
||||
case 0x6C:
|
||||
|
||||
M_LDWORD(K);
|
||||
|
||||
R->PC.B.l = Rd6502(K.W);
|
||||
|
||||
K.B.l++;
|
||||
|
||||
R->PC.B.h = Rd6502(K.W);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
/* BRK */
|
||||
case 0x00:
|
||||
|
||||
R->PC.W++;
|
||||
|
||||
M_PUSH(R->PC.B.h);
|
||||
M_PUSH(R->PC.B.l);
|
||||
|
||||
M_PUSH(R->P | B_FLAG);
|
||||
|
||||
R->P = (R->P | I_FLAG) & ~D_FLAG;
|
||||
|
||||
R->PC.B.l = Rd6502(0xFFFE);
|
||||
|
||||
R->PC.B.h = Rd6502(0xFFFF);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
/* CLI */
|
||||
case 0x58:
|
||||
|
||||
if ((R->IRequest != INT_NONE) && (R->P & I_FLAG))
|
||||
|
||||
{
|
||||
|
||||
R->AfterCLI = 1;
|
||||
|
||||
R->IBackup = R->ICount;
|
||||
|
||||
R->ICount = 1;
|
||||
|
||||
}
|
||||
R->P &= ~I_FLAG;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
/* PLP */
|
||||
case 0x28:
|
||||
|
||||
M_POP(I);
|
||||
|
||||
if ((R->IRequest != INT_NONE) && ((I ^ R->P) & ~I & I_FLAG))
|
||||
|
||||
{
|
||||
|
||||
R->AfterCLI = 1;
|
||||
|
||||
R->IBackup = R->ICount;
|
||||
|
||||
R->ICount = 1;
|
||||
|
||||
}
|
||||
R->P = I | R_FLAG | B_FLAG;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 0x08:
|
||||
M_PUSH(R->P);
|
||||
break; /* PHP */
|
||||
|
||||
case 0x18:
|
||||
R->P &= ~C_FLAG;
|
||||
break; /* CLC */
|
||||
|
||||
case 0xB8:
|
||||
R->P &= ~V_FLAG;
|
||||
break; /* CLV */
|
||||
|
||||
case 0xD8:
|
||||
R->P &= ~D_FLAG;
|
||||
break; /* CLD */
|
||||
|
||||
case 0x38:
|
||||
R->P |= C_FLAG;
|
||||
break; /* SEC */
|
||||
|
||||
case 0xF8:
|
||||
R->P |= D_FLAG;
|
||||
break; /* SED */
|
||||
|
||||
case 0x78:
|
||||
R->P |= I_FLAG;
|
||||
break; /* SEI */
|
||||
|
||||
case 0x48:
|
||||
M_PUSH(R->A);
|
||||
break; /* PHA */
|
||||
|
||||
case 0x68:
|
||||
M_POP(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* PLA */
|
||||
|
||||
case 0x98:
|
||||
R->A = R->Y;
|
||||
M_FL(R->A);
|
||||
break; /* TYA */
|
||||
|
||||
case 0xA8:
|
||||
R->Y = R->A;
|
||||
M_FL(R->Y);
|
||||
break; /* TAY */
|
||||
|
||||
case 0xC8:
|
||||
R->Y++;
|
||||
M_FL(R->Y);
|
||||
break; /* INY */
|
||||
|
||||
case 0x88:
|
||||
R->Y--;
|
||||
M_FL(R->Y);
|
||||
break; /* DEY */
|
||||
|
||||
case 0x8A:
|
||||
R->A = R->X;
|
||||
M_FL(R->A);
|
||||
break; /* TXA */
|
||||
|
||||
case 0xAA:
|
||||
R->X = R->A;
|
||||
M_FL(R->X);
|
||||
break; /* TAX */
|
||||
|
||||
case 0xE8:
|
||||
R->X++;
|
||||
M_FL(R->X);
|
||||
break; /* INX */
|
||||
|
||||
case 0xCA:
|
||||
R->X--;
|
||||
M_FL(R->X);
|
||||
break; /* DEX */
|
||||
|
||||
default: /* In CMOS version unrecognized instructions are concidered as
|
||||
NOP */
|
||||
case 0xEA:
|
||||
break; /* NOP */
|
||||
|
||||
case 0x9A:
|
||||
R->S = R->X;
|
||||
break; /* TXS */
|
||||
|
||||
case 0xBA:
|
||||
R->X = R->S;
|
||||
M_FL(R->X);
|
||||
break; /* TSX */
|
||||
|
||||
|
||||
case 0x24:
|
||||
MR_Zp(I);
|
||||
M_BIT(I);
|
||||
break; /* BIT $ss ZP */
|
||||
|
||||
case 0x2C:
|
||||
MR_Ab(I);
|
||||
M_BIT(I);
|
||||
break; /* BIT $ssss ABS */
|
||||
|
||||
|
||||
case 0x05:
|
||||
MR_Zp(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA $ss ZP */
|
||||
|
||||
case 0x06:
|
||||
MM_Zp(M_ASL);
|
||||
break; /* ASL $ss ZP */
|
||||
|
||||
case 0x25:
|
||||
MR_Zp(I);
|
||||
M_AND(I);
|
||||
break; /* AND $ss ZP */
|
||||
|
||||
case 0x26:
|
||||
MM_Zp(M_ROL);
|
||||
break; /* ROL $ss ZP */
|
||||
|
||||
case 0x45:
|
||||
MR_Zp(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR $ss ZP */
|
||||
|
||||
case 0x46:
|
||||
MM_Zp(M_LSR);
|
||||
break; /* LSR $ss ZP */
|
||||
|
||||
case 0x65:
|
||||
MR_Zp(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC $ss ZP */
|
||||
|
||||
case 0x66:
|
||||
MM_Zp(M_ROR);
|
||||
break; /* ROR $ss ZP */
|
||||
|
||||
case 0x84:
|
||||
MW_Zp(R->Y);
|
||||
break; /* STY $ss ZP */
|
||||
|
||||
case 0x85:
|
||||
MW_Zp(R->A);
|
||||
break; /* STA $ss ZP */
|
||||
|
||||
case 0x86:
|
||||
MW_Zp(R->X);
|
||||
break; /* STX $ss ZP */
|
||||
|
||||
case 0xA4:
|
||||
MR_Zp(R->Y);
|
||||
M_FL(R->Y);
|
||||
break; /* LDY $ss ZP */
|
||||
|
||||
case 0xA5:
|
||||
MR_Zp(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA $ss ZP */
|
||||
|
||||
case 0xA6:
|
||||
MR_Zp(R->X);
|
||||
M_FL(R->X);
|
||||
break; /* LDX $ss ZP */
|
||||
|
||||
case 0xC4:
|
||||
MR_Zp(I);
|
||||
M_CMP(R->Y, I);
|
||||
break; /* CPY $ss ZP */
|
||||
|
||||
case 0xC5:
|
||||
MR_Zp(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP $ss ZP */
|
||||
|
||||
case 0xC6:
|
||||
MM_Zp(M_DEC);
|
||||
break; /* DEC $ss ZP */
|
||||
|
||||
case 0xE4:
|
||||
MR_Zp(I);
|
||||
M_CMP(R->X, I);
|
||||
break; /* CPX $ss ZP */
|
||||
|
||||
case 0xE5:
|
||||
MR_Zp(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC $ss ZP */
|
||||
|
||||
case 0xE6:
|
||||
MM_Zp(M_INC);
|
||||
break; /* INC $ss ZP */
|
||||
|
||||
|
||||
case 0x0D:
|
||||
MR_Ab(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA $ssss ABS */
|
||||
|
||||
case 0x0E:
|
||||
MM_Ab(M_ASL);
|
||||
break; /* ASL $ssss ABS */
|
||||
|
||||
case 0x2D:
|
||||
MR_Ab(I);
|
||||
M_AND(I);
|
||||
break; /* AND $ssss ABS */
|
||||
|
||||
case 0x2E:
|
||||
MM_Ab(M_ROL);
|
||||
break; /* ROL $ssss ABS */
|
||||
|
||||
case 0x4D:
|
||||
MR_Ab(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR $ssss ABS */
|
||||
|
||||
case 0x4E:
|
||||
MM_Ab(M_LSR);
|
||||
break; /* LSR $ssss ABS */
|
||||
|
||||
case 0x6D:
|
||||
MR_Ab(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC $ssss ABS */
|
||||
|
||||
case 0x6E:
|
||||
MM_Ab(M_ROR);
|
||||
break; /* ROR $ssss ABS */
|
||||
|
||||
case 0x8C:
|
||||
MW_Ab(R->Y);
|
||||
break; /* STY $ssss ABS */
|
||||
|
||||
case 0x8D:
|
||||
MW_Ab(R->A);
|
||||
break; /* STA $ssss ABS */
|
||||
|
||||
case 0x8E:
|
||||
MW_Ab(R->X);
|
||||
break; /* STX $ssss ABS */
|
||||
|
||||
case 0xAC:
|
||||
MR_Ab(R->Y);
|
||||
M_FL(R->Y);
|
||||
break; /* LDY $ssss ABS */
|
||||
|
||||
case 0xAD:
|
||||
MR_Ab(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA $ssss ABS */
|
||||
|
||||
case 0xAE:
|
||||
MR_Ab(R->X);
|
||||
M_FL(R->X);
|
||||
break; /* LDX $ssss ABS */
|
||||
|
||||
case 0xCC:
|
||||
MR_Ab(I);
|
||||
M_CMP(R->Y, I);
|
||||
break; /* CPY $ssss ABS */
|
||||
|
||||
case 0xCD:
|
||||
MR_Ab(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP $ssss ABS */
|
||||
|
||||
case 0xCE:
|
||||
MM_Ab(M_DEC);
|
||||
break; /* DEC $ssss ABS */
|
||||
|
||||
case 0xEC:
|
||||
MR_Ab(I);
|
||||
M_CMP(R->X, I);
|
||||
break; /* CPX $ssss ABS */
|
||||
|
||||
case 0xED:
|
||||
MR_Ab(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC $ssss ABS */
|
||||
|
||||
case 0xEE:
|
||||
MM_Ab(M_INC);
|
||||
break; /* INC $ssss ABS */
|
||||
|
||||
|
||||
case 0x09:
|
||||
MR_Im(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA #$ss IMM */
|
||||
|
||||
case 0x29:
|
||||
MR_Im(I);
|
||||
M_AND(I);
|
||||
break; /* AND #$ss IMM */
|
||||
|
||||
case 0x49:
|
||||
MR_Im(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR #$ss IMM */
|
||||
|
||||
case 0x69:
|
||||
MR_Im(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC #$ss IMM */
|
||||
|
||||
case 0xA0:
|
||||
MR_Im(R->Y);
|
||||
M_FL(R->Y);
|
||||
break; /* LDY #$ss IMM */
|
||||
|
||||
case 0xA2:
|
||||
MR_Im(R->X);
|
||||
M_FL(R->X);
|
||||
break; /* LDX #$ss IMM */
|
||||
|
||||
case 0xA9:
|
||||
MR_Im(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA #$ss IMM */
|
||||
|
||||
case 0xC0:
|
||||
MR_Im(I);
|
||||
M_CMP(R->Y, I);
|
||||
break; /* CPY #$ss IMM */
|
||||
|
||||
case 0xC9:
|
||||
MR_Im(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP #$ss IMM */
|
||||
|
||||
case 0xE0:
|
||||
MR_Im(I);
|
||||
M_CMP(R->X, I);
|
||||
break; /* CPX #$ss IMM */
|
||||
|
||||
case 0xE9:
|
||||
MR_Im(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC #$ss IMM */
|
||||
|
||||
|
||||
case 0x15:
|
||||
MR_Zx(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA $ss,x ZP,x */
|
||||
|
||||
case 0x16:
|
||||
MM_Zx(M_ASL);
|
||||
break; /* ASL $ss,x ZP,x */
|
||||
|
||||
case 0x35:
|
||||
MR_Zx(I);
|
||||
M_AND(I);
|
||||
break; /* AND $ss,x ZP,x */
|
||||
|
||||
case 0x36:
|
||||
MM_Zx(M_ROL);
|
||||
break; /* ROL $ss,x ZP,x */
|
||||
|
||||
case 0x55:
|
||||
MR_Zx(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR $ss,x ZP,x */
|
||||
|
||||
case 0x56:
|
||||
MM_Zx(M_LSR);
|
||||
break; /* LSR $ss,x ZP,x */
|
||||
|
||||
case 0x75:
|
||||
MR_Zx(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC $ss,x ZP,x */
|
||||
|
||||
case 0x76:
|
||||
MM_Zx(M_ROR);
|
||||
break; /* ROR $ss,x ZP,x */
|
||||
|
||||
case 0x94:
|
||||
MW_Zx(R->Y);
|
||||
break; /* STY $ss,x ZP,x */
|
||||
|
||||
case 0x95:
|
||||
MW_Zx(R->A);
|
||||
break; /* STA $ss,x ZP,x */
|
||||
|
||||
case 0x96:
|
||||
MW_Zy(R->X);
|
||||
break; /* STX $ss,y ZP,y */
|
||||
|
||||
case 0xB4:
|
||||
MR_Zx(R->Y);
|
||||
M_FL(R->Y);
|
||||
break; /* LDY $ss,x ZP,x */
|
||||
|
||||
case 0xB5:
|
||||
MR_Zx(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA $ss,x ZP,x */
|
||||
|
||||
case 0xB6:
|
||||
MR_Zy(R->X);
|
||||
M_FL(R->X);
|
||||
break; /* LDX $ss,y ZP,y */
|
||||
|
||||
case 0xD5:
|
||||
MR_Zx(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP $ss,x ZP,x */
|
||||
|
||||
case 0xD6:
|
||||
MM_Zx(M_DEC);
|
||||
break; /* DEC $ss,x ZP,x */
|
||||
|
||||
case 0xF5:
|
||||
MR_Zx(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC $ss,x ZP,x */
|
||||
|
||||
case 0xF6:
|
||||
MM_Zx(M_INC);
|
||||
break; /* INC $ss,x ZP,x */
|
||||
|
||||
|
||||
case 0x19:
|
||||
MR_Ay(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA $ssss,y ABS,y */
|
||||
|
||||
case 0x1D:
|
||||
MR_Ax(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA $ssss,x ABS,x */
|
||||
|
||||
case 0x1E:
|
||||
MM_Ax(M_ASL);
|
||||
break; /* ASL $ssss,x ABS,x */
|
||||
|
||||
case 0x39:
|
||||
MR_Ay(I);
|
||||
M_AND(I);
|
||||
break; /* AND $ssss,y ABS,y */
|
||||
|
||||
case 0x3D:
|
||||
MR_Ax(I);
|
||||
M_AND(I);
|
||||
break; /* AND $ssss,x ABS,x */
|
||||
|
||||
case 0x3E:
|
||||
MM_Ax(M_ROL);
|
||||
break; /* ROL $ssss,x ABS,x */
|
||||
|
||||
case 0x59:
|
||||
MR_Ay(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR $ssss,y ABS,y */
|
||||
|
||||
case 0x5D:
|
||||
MR_Ax(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR $ssss,x ABS,x */
|
||||
|
||||
case 0x5E:
|
||||
MM_Ax(M_LSR);
|
||||
break; /* LSR $ssss,x ABS,x */
|
||||
|
||||
case 0x79:
|
||||
MR_Ay(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC $ssss,y ABS,y */
|
||||
|
||||
case 0x7D:
|
||||
MR_Ax(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC $ssss,x ABS,x */
|
||||
|
||||
case 0x7E:
|
||||
MM_Ax(M_ROR);
|
||||
break; /* ROR $ssss,x ABS,x */
|
||||
|
||||
case 0x99:
|
||||
MW_Ay(R->A);
|
||||
break; /* STA $ssss,y ABS,y */
|
||||
|
||||
case 0x9D:
|
||||
MW_Ax(R->A);
|
||||
break; /* STA $ssss,x ABS,x */
|
||||
|
||||
case 0xB9:
|
||||
MR_Ay(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA $ssss,y ABS,y */
|
||||
|
||||
case 0xBC:
|
||||
MR_Ax(R->Y);
|
||||
M_FL(R->Y);
|
||||
break; /* LDY $ssss,x ABS,x */
|
||||
|
||||
case 0xBD:
|
||||
MR_Ax(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA $ssss,x ABS,x */
|
||||
|
||||
case 0xBE:
|
||||
MR_Ay(R->X);
|
||||
M_FL(R->X);
|
||||
break; /* LDX $ssss,y ABS,y */
|
||||
|
||||
case 0xD9:
|
||||
MR_Ay(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP $ssss,y ABS,y */
|
||||
|
||||
case 0xDD:
|
||||
MR_Ax(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP $ssss,x ABS,x */
|
||||
|
||||
case 0xDE:
|
||||
MM_Ax(M_DEC);
|
||||
break; /* DEC $ssss,x ABS,x */
|
||||
|
||||
case 0xF9:
|
||||
MR_Ay(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC $ssss,y ABS,y */
|
||||
|
||||
case 0xFD:
|
||||
MR_Ax(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC $ssss,x ABS,x */
|
||||
|
||||
case 0xFE:
|
||||
MM_Ax(M_INC);
|
||||
break; /* INC $ssss,x ABS,x */
|
||||
|
||||
|
||||
case 0x01:
|
||||
MR_Ix(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0x11:
|
||||
MR_Iy(I);
|
||||
M_ORA(I);
|
||||
break; /* ORA ($ss),y INDIRINDEX */
|
||||
|
||||
case 0x21:
|
||||
MR_Ix(I);
|
||||
M_AND(I);
|
||||
break; /* AND ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0x31:
|
||||
MR_Iy(I);
|
||||
M_AND(I);
|
||||
break; /* AND ($ss),y INDIRINDEX */
|
||||
|
||||
case 0x41:
|
||||
MR_Ix(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0x51:
|
||||
MR_Iy(I);
|
||||
M_EOR(I);
|
||||
break; /* EOR ($ss),y INDIRINDEX */
|
||||
|
||||
case 0x61:
|
||||
MR_Ix(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0x71:
|
||||
MR_Iy(I);
|
||||
M_ADC(I);
|
||||
break; /* ADC ($ss),y INDIRINDEX */
|
||||
|
||||
case 0x81:
|
||||
MW_Ix(R->A);
|
||||
break; /* STA ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0x91:
|
||||
MW_Iy(R->A);
|
||||
break; /* STA ($ss),y INDIRINDEX */
|
||||
|
||||
case 0xA1:
|
||||
MR_Ix(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0xB1:
|
||||
MR_Iy(R->A);
|
||||
M_FL(R->A);
|
||||
break; /* LDA ($ss),y INDIRINDEX */
|
||||
|
||||
case 0xC1:
|
||||
MR_Ix(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0xD1:
|
||||
MR_Iy(I);
|
||||
M_CMP(R->A, I);
|
||||
break; /* CMP ($ss),y INDIRINDEX */
|
||||
|
||||
case 0xE1:
|
||||
MR_Ix(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC ($ss,x) INDEXINDIR */
|
||||
|
||||
case 0xF1:
|
||||
MR_Iy(I);
|
||||
M_SBC(I);
|
||||
break; /* SBC ($ss),y INDIRINDEX */
|
||||
|
||||
|
||||
case 0x0A:
|
||||
M_ASL(R->A);
|
||||
break; /* ASL a ACC */
|
||||
|
||||
case 0x2A:
|
||||
M_ROL(R->A);
|
||||
break; /* ROL a ACC */
|
||||
|
||||
case 0x4A:
|
||||
M_LSR(R->A);
|
||||
break; /* LSR a ACC */
|
||||
|
||||
case 0x6A:
|
||||
M_ROR(R->A);
|
||||
break; /* ROR a ACC */
|
||||
|
||||
480
src/corecpu/Debug.c
Executable file
480
src/corecpu/Debug.c
Executable file
@ -0,0 +1,480 @@
|
||||
/** M6502: portable 6502 emulator ****************************/
|
||||
/** **/
|
||||
/** Debug.c **/
|
||||
/** **/
|
||||
/** This file contains the built-in debugging routine for **/
|
||||
/** the 6502 emulator which is called on each 6502 step **/
|
||||
/** when Trap!=0. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-1997 **/
|
||||
/** Alex Krasivsky 1996 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
/*
|
||||
* $LastChangedDate: 2007-04-19 18:18:57 +0200 (jeu, 19 avr 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/Debug.c $
|
||||
* $Revision: 43 $
|
||||
*/
|
||||
|
||||
#include "M6502.h"
|
||||
#ifdef DEBUG
|
||||
#include <allegro.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <ppu/ppu.h>
|
||||
|
||||
#include <Sound.h>
|
||||
|
||||
#define RDWORD(A) (Rd6502(A+1)*256+Rd6502(A))
|
||||
|
||||
extern unsigned char *Memory;
|
||||
|
||||
void showlastop();
|
||||
|
||||
enum Addressing_Modes
|
||||
{
|
||||
Ac = 0, Il, Im, Ab, Zp, Zx, Zy, Ax, Ay, Rl, Ix, Iy, In, No
|
||||
};
|
||||
|
||||
|
||||
|
||||
static byte *mn[] =
|
||||
{
|
||||
"adc ", "and ", "asl ", "bcc ", "bcs ", "beq ", "bit ", "bmi ",
|
||||
"bne ", "bpl ", "brk", "bvc ", "bvs ", "clc", "cld", "cli",
|
||||
"clv", "cmp ", "cpx ", "cpy ", "dec ", "dex", "dey", "inx",
|
||||
"iny", "eor ", "inc ", "jmp ", "jsr ", "lda ", "nop ", "ldx ",
|
||||
"ldy ", "lsr ", "ora ", "pha", "php", "pla", "plp", "rol ",
|
||||
"ror ", "rti", "rts", "sbc ", "sta ", "stx ", "sty ", "sec ",
|
||||
"sed", "sei", "tax", "tay", "txa", "tya", "tsx", "txs"
|
||||
};
|
||||
|
||||
|
||||
|
||||
static byte ad[512] =
|
||||
{
|
||||
10, Il, 34, Ix, No, No, No, No, No, No, 34, Zp, 2, Zp, No, No,
|
||||
36, Il, 34, Im, 2, Ac, No, No, No, No, 34, Ab, 2, Ab, No, No,
|
||||
9, Rl, 34, Iy, No, No, No, No, No, No, 34, Zx, 2, Zx, No, No,
|
||||
13, Il, 34, Ay, No, No, No, No, No, No, 34, Ax, 2, Ax, No, No,
|
||||
28, Ab, 1, Ix, No, No, No, No, 6, Zp, 1, Zp, 39, Zp, No, No,
|
||||
38, Il, 1, Im, 39, Ac, No, No, 6, Ab, 1, Ab, 39, Ab, No, No,
|
||||
7, Rl, 1, Iy, No, No, No, No, No, No, 1, Zx, 39, Zx, No, No,
|
||||
47, Il, 1, Ay, No, No, No, No, No, No, 1, Ax, 39, Ax, No, No,
|
||||
41, Il, 25, Ix, No, No, No, No, No, No, 25, Zp, 33, Zp, No, No,
|
||||
35, Il, 25, Im, 33, Ac, No, No, 27, Ab, 25, Ab, 33, Ab, No, No,
|
||||
11, Rl, 25, Iy, No, No, No, No, No, No, 25, Zx, 33, Zx, No, No,
|
||||
15, Il, 25, Ay, No, No, No, No, No, No, 25, Ax, 33, Ax, No, No,
|
||||
42, Il, 0, Ix, No, No, No, No, No, No, 0, Zp, 40, Zp, No, No,
|
||||
37, Il, 0, Im, 40, Ac, No, No, 27, In, 0, Ab, 40, Ab, No, No,
|
||||
12, Rl, 0, Iy, No, No, No, No, No, No, 0, Zx, 40, Zx, No, No,
|
||||
49, Il, 0, Ay, No, No, No, No, No, No, 0, Ax, 40, Ax, No, No,
|
||||
No, No, 44, Ix, No, No, No, No, 46, Zp, 44, Zp, 45, Zp, No, No,
|
||||
22, Il, No, No, 52, Il, No, No, 46, Ab, 44, Ab, 45, Ab, No, No,
|
||||
3, Rl, 44, Iy, No, No, No, No, 46, Zx, 44, Zx, 45, Zy, No, No,
|
||||
53, Il, 44, Ay, 55, Il, No, No, No, No, 44, Ax, No, No, No, No,
|
||||
32, Im, 29, Ix, 31, Im, No, No, 32, Zp, 29, Zp, 31, Zp, No, No,
|
||||
51, Il, 29, Im, 50, Il, No, No, 32, Ab, 29, Ab, 31, Ab, No, No,
|
||||
4, Rl, 29, Iy, No, No, No, No, 32, Zx, 29, Zx, 31, Zy, No, No,
|
||||
16, Il, 29, Ay, 54, Il, No, No, 32, Ax, 29, Ax, 31, Ay, No, No,
|
||||
19, Im, 17, Ix, No, No, No, No, 19, Zp, 17, Zp, 20, Zp, No, No,
|
||||
24, Il, 17, Im, 21, Il, No, No, 19, Ab, 17, Ab, 20, Ab, No, No,
|
||||
8, Rl, 17, Iy, No, No, No, No, No, No, 17, Zx, 20, Zx, No, No,
|
||||
14, Il, 17, Ay, No, No, No, No, No, No, 17, Ax, 20, Ax, No, No,
|
||||
18, Im, 43, Ix, No, No, No, No, 18, Zp, 43, Zp, 26, Zp, No, No,
|
||||
23, Il, 43, Im, 30, Il, No, No, 18, Ab, 43, Ab, 26, Ab, No, No,
|
||||
5, Rl, 43, Iy, No, No, No, No, No, No, 43, Zx, 26, Zx, No, No,
|
||||
48, Il, 43, Ay, No, No, No, No, No, No, 43, Ax, 26, Ax, No, No
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** DAsm() ****************************************************/
|
||||
/** This function will disassemble a single command and **/
|
||||
/** return the number of bytes disassembled. **/
|
||||
/**************************************************************/
|
||||
int DAsm(char *S, word A)
|
||||
{
|
||||
|
||||
byte J;
|
||||
|
||||
word B, OP, TO;
|
||||
|
||||
|
||||
B = A;
|
||||
OP = Rd6502(B++) * 2;
|
||||
|
||||
|
||||
switch (ad[OP + 1])
|
||||
|
||||
{
|
||||
|
||||
case Ac:
|
||||
sprintf(S, "%s a", mn[ad[OP]]);
|
||||
break;
|
||||
|
||||
case Il:
|
||||
sprintf(S, "%s", mn[ad[OP]]);
|
||||
break;
|
||||
|
||||
|
||||
case Rl:
|
||||
J = Rd6502(B++);
|
||||
TO = A + 2 + ((J < 0x80) ? J : (J - 256));
|
||||
|
||||
sprintf(S, "%s $%04X", mn[ad[OP]], TO);
|
||||
break;
|
||||
|
||||
|
||||
case Im:
|
||||
sprintf(S, "%s #$%02X", mn[ad[OP]], Rd6502(B++));
|
||||
break;
|
||||
|
||||
case Zp:
|
||||
sprintf(S, "%s $%02X", mn[ad[OP]], Rd6502(B++));
|
||||
break;
|
||||
|
||||
case Zx:
|
||||
sprintf(S, "%s $%02X,x", mn[ad[OP]], Rd6502(B++));
|
||||
break;
|
||||
|
||||
case Zy:
|
||||
sprintf(S, "%s $%02X,y", mn[ad[OP]], Rd6502(B++));
|
||||
break;
|
||||
|
||||
case Ix:
|
||||
sprintf(S, "%s ($%02X,x)", mn[ad[OP]], Rd6502(B++));
|
||||
break;
|
||||
|
||||
case Iy:
|
||||
sprintf(S, "%s ($%02X),y", mn[ad[OP]], Rd6502(B++));
|
||||
break;
|
||||
|
||||
|
||||
case Ab:
|
||||
sprintf(S, "%s $%04X", mn[ad[OP]], RDWORD(B));
|
||||
B += 2;
|
||||
break;
|
||||
|
||||
case Ax:
|
||||
sprintf(S, "%s $%04X,x", mn[ad[OP]], RDWORD(B));
|
||||
B += 2;
|
||||
break;
|
||||
|
||||
case Ay:
|
||||
sprintf(S, "%s $%04X,y", mn[ad[OP]], RDWORD(B));
|
||||
B += 2;
|
||||
break;
|
||||
|
||||
case In:
|
||||
sprintf(S, "%s ($%04X)", mn[ad[OP]], RDWORD(B));
|
||||
B += 2;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
sprintf(S, ".db $%02X; <Invalid OPcode>", OP / 2);
|
||||
|
||||
}
|
||||
return (B - A);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Debug6502() **********************************************/
|
||||
/** This function should exist if DEBUG is #defined. When **/
|
||||
/** Trace!=0, it is called after each command executed by **/
|
||||
/** the CPU, and given the 6502 registers. Emulation exits **/
|
||||
/** if Debug6502() returns 0. **/
|
||||
/*************************************************************/
|
||||
byte Debug6502(M6502 * R)
|
||||
{
|
||||
static char FA[8] = "NVRBDIZC";
|
||||
char S[128];
|
||||
byte F;
|
||||
int J, I;
|
||||
|
||||
DAsm(S, R->PC.W);
|
||||
|
||||
printf
|
||||
(
|
||||
"A:%02X P:%02X X:%02X Y:%02X S:%04X PC:%04X Flags:[",
|
||||
R->A, R->P, R->X, R->Y, R->S + 0x0100, R->PC.W
|
||||
);
|
||||
|
||||
|
||||
for (J = 0, F = R->P; J < 8; J++, F <<= 1)
|
||||
|
||||
printf("%c", F & 0x80 ? FA[J] : '.');
|
||||
|
||||
puts("]");
|
||||
|
||||
|
||||
printf
|
||||
(
|
||||
"AT PC: [%02X - %s] AT SP: [%02X %02X %02X]\n",
|
||||
Rd6502(R->PC.W), S,
|
||||
Rd6502(0x0100 + (byte) (R->S + 1)),
|
||||
Rd6502(0x0100 + (byte) (R->S + 2)),
|
||||
Rd6502(0x0100 + (byte) (R->S + 3))
|
||||
);
|
||||
|
||||
|
||||
sprintf(S, "");
|
||||
remove_keyboard();
|
||||
|
||||
#ifdef USE_SOUND
|
||||
StopSound();
|
||||
#endif
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf("\n[Command,'?']-> ");
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stdin);
|
||||
|
||||
|
||||
fgets(S, 50, stdin);
|
||||
|
||||
for (J = 0; S[J] >= ' '; J++)
|
||||
S[J] = toupper(S[J]);
|
||||
|
||||
S[J] = '\0';
|
||||
|
||||
|
||||
switch (S[0])
|
||||
{
|
||||
case 'H':
|
||||
case '?':
|
||||
puts("\n***** Built-in 6502 Debugger Commands *****");
|
||||
puts("<CR> : Break at the next instruction");
|
||||
puts("= <addr> : Break at addr");
|
||||
puts("+ <offset> : Break at PC + offset");
|
||||
puts("t <addr> : Set PC to addr");
|
||||
puts("c : Continue without break");
|
||||
puts("j <addr> : Continue from addr");
|
||||
puts("m <addr> : Memory dump at addr");
|
||||
puts("d <addr> : Disassembly at addr");
|
||||
puts("v : Show ;interrupt vectors");
|
||||
puts("?,h : Show this help text");
|
||||
puts("r : Show Register Status");
|
||||
puts("q : Exit 6502 emulation");
|
||||
|
||||
puts("----- TI-NES Specific -----");
|
||||
puts("w : Dump Memory State");
|
||||
puts("o : Show PPU registers");
|
||||
puts("p <addr> : Dump PPU memory at addr");
|
||||
puts("a : Dump all memory to memory.log");
|
||||
puts("s : Dump sprite table to sprite.log");
|
||||
puts("n <nb> : Dump name table <nb> to nt.log");
|
||||
puts("z : Show lastest opcode executed");
|
||||
puts("i : SpriteTable Dump");
|
||||
puts("g <nb> : Get sprite <nb> info");
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
return (1);
|
||||
|
||||
case 'Z':
|
||||
showlastop();
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
DumpMemoryState(stdout);
|
||||
break;
|
||||
|
||||
|
||||
case 'A':
|
||||
{
|
||||
|
||||
FILE * fpDmpMem;
|
||||
|
||||
if ((fpDmpMem = fopen("memory.log", "wb")) != NULL)
|
||||
|
||||
{
|
||||
|
||||
// fwrite(Memory, 1, 0x8000, fpDmpMem);
|
||||
//fwrite(mLBank, 1, 0x4000, fpDmpMem);
|
||||
//fwrite(mUBank, 1, 0x4000, fpDmpMem);
|
||||
|
||||
fclose(fpDmpMem);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case '=':
|
||||
if (strlen(S) >= 2)
|
||||
|
||||
{
|
||||
sscanf(S + 1, "%hX", &(R->Trap));
|
||||
R->Trace = 0;
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (strlen(S) >= 2)
|
||||
|
||||
{
|
||||
|
||||
sscanf(S + 1, "%hX", &(R->Trap));
|
||||
|
||||
R->Trap += R->PC.W;
|
||||
R->Trace = 0;
|
||||
|
||||
return (1);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
if (strlen(S) >= 2)
|
||||
|
||||
{
|
||||
sscanf(S + 1, "%hX", &(R->PC.W));
|
||||
R->Trace = 0;
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
if (strlen(S) >= 2)
|
||||
|
||||
{
|
||||
sscanf(S + 1, "%hX", &(R->PC.W));
|
||||
R->Trace = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
R->Trap = 0xFFFF;
|
||||
R->Trace = 0;
|
||||
install_keyboard();
|
||||
|
||||
//ResumeSound();
|
||||
|
||||
SetSound(0, SND_RECTANGLE);
|
||||
SetSound(1, SND_RECTANGLE);
|
||||
SetSound(2, SND_TRIANGLE);
|
||||
SetSound(3, SND_NOISE);
|
||||
|
||||
return (1);
|
||||
|
||||
case 'Q':
|
||||
return (0);
|
||||
|
||||
|
||||
case 'V':
|
||||
puts("\n6502 Interrupt Vectors:");
|
||||
printf("[$FFFC] INIT: $%04X\n", Rd6502(0xFFFC) + 256 * Rd6502(0xFFFD));
|
||||
printf("[$FFFE] IRQ: $%04X\n", Rd6502(0xFFFE) + 256 * Rd6502(0xFFFF));
|
||||
printf("[$FFFA] NMI: $%04X\n", Rd6502(0xFFFA) + 256 * Rd6502(0xFFFB));
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
{
|
||||
word Addr;
|
||||
|
||||
if (strlen(S) > 1)
|
||||
sscanf(S + 1, "%hX", &Addr);
|
||||
else
|
||||
Addr = R->PC.W;
|
||||
puts("");
|
||||
for (J = 0; J < 16; J++)
|
||||
{
|
||||
printf("%04X: ", Addr);
|
||||
for (I = 0; I < 16; I++, Addr++)
|
||||
|
||||
printf("%02X ", Rd6502(Addr));
|
||||
|
||||
printf(" | ");
|
||||
Addr -= 16;
|
||||
|
||||
for (I = 0; I < 16; I++, Addr++)
|
||||
|
||||
putchar(isprint(Rd6502(Addr)) ? Rd6502(Addr) : '.');
|
||||
|
||||
puts("");
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
|
||||
printf
|
||||
(
|
||||
"A:%02X P:%02X X:%02X Y:%02X S:%04X PC:%04X Flags:[",
|
||||
R->A, R->P, R->X, R->Y, R->S + 0x0100, R->PC.W
|
||||
);
|
||||
|
||||
|
||||
for (J = 0, F = R->P; J < 8; J++, F <<= 1)
|
||||
|
||||
printf("%c", F & 0x80 ? FA[J] : '.');
|
||||
|
||||
puts("]");
|
||||
|
||||
|
||||
printf
|
||||
(
|
||||
"AT PC: [%02X - %s] AT SP: [%02X %02X %02X]\n",
|
||||
Rd6502(R->PC.W), S,
|
||||
Rd6502(0x0100 + (byte) (R->S + 1)),
|
||||
Rd6502(0x0100 + (byte) (R->S + 2)),
|
||||
Rd6502(0x0100 + (byte) (R->S + 3))
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 'D':
|
||||
|
||||
{
|
||||
|
||||
word Addr;
|
||||
|
||||
|
||||
if (strlen(S) > 1)
|
||||
sscanf(S + 1, "%hX", &Addr);
|
||||
else
|
||||
Addr = R->PC.W;
|
||||
|
||||
puts("");
|
||||
|
||||
for (J = 0; J < 16; J++)
|
||||
|
||||
{
|
||||
|
||||
printf("%04X: ", Addr);
|
||||
|
||||
Addr += DAsm(S, Addr);
|
||||
|
||||
puts(S);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Continue with emulation */
|
||||
return (1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* DEBUG */
|
||||
317
src/corecpu/M6502.c
Executable file
317
src/corecpu/M6502.c
Executable file
@ -0,0 +1,317 @@
|
||||
/** M6502: portable 6502 emulator ****************************/
|
||||
/** **/
|
||||
/** M6502.c **/
|
||||
/** **/
|
||||
/** This file contains implementation for 6502 CPU. Don't **/
|
||||
/** forget to provide Rd6502(), Wr6502(), Loop6502(), and **/
|
||||
/** possibly Op6502() functions to accomodate the emulated **/
|
||||
/** machine's architecture. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2002 **/
|
||||
/** Alex Krasivsky 1996 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
/*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/M6502.c $
|
||||
* $Revision: 39 $
|
||||
*/
|
||||
|
||||
#include "M6502.h"
|
||||
#include "Tables.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/** INLINE ***************************************************/
|
||||
/** Different compilers inline C functions differently. **/
|
||||
/*************************************************************/
|
||||
#ifdef __GNUC__
|
||||
#define INLINE inline
|
||||
#else
|
||||
#define INLINE static
|
||||
#endif
|
||||
|
||||
int icount = 0;
|
||||
|
||||
/** System-Dependent Stuff ***********************************/
|
||||
/** This is system-dependent code put here to speed things **/
|
||||
/** up. It has to stay inlined to be fast. **/
|
||||
/*************************************************************/
|
||||
#ifdef INES
|
||||
#define FAST_RDOP
|
||||
extern byte *Page[];
|
||||
INLINE byte Op6502(register word A) { return(Page[A>>13][A&0x1FFF]); }
|
||||
#endif
|
||||
|
||||
/** FAST_RDOP ************************************************/
|
||||
/** With this #define not present, Rd6502() should perform **/
|
||||
/** the functions of Rd6502(). **/
|
||||
/*************************************************************/
|
||||
#ifndef FAST_RDOP
|
||||
#define Op6502(A) Rd6502(A)
|
||||
#endif
|
||||
|
||||
/** Addressing Methods ***************************************/
|
||||
/** These macros calculate and return effective addresses. **/
|
||||
/*************************************************************/
|
||||
#define MC_Ab(Rg) M_LDWORD(Rg)
|
||||
#define MC_Zp(Rg) Rg.W=Op6502(R->PC.W++)
|
||||
#define MC_Zx(Rg) Rg.W=(byte)(Op6502(R->PC.W++)+R->X)
|
||||
#define MC_Zy(Rg) Rg.W=(byte)(Op6502(R->PC.W++)+R->Y)
|
||||
#define MC_Ax(Rg) M_LDWORD(Rg);Rg.W+=R->X
|
||||
#define MC_Ay(Rg) M_LDWORD(Rg);Rg.W+=R->Y
|
||||
#define MC_Ix(Rg) K.W=(byte)(Op6502(R->PC.W++)+R->X); \
|
||||
Rg.B.l=Op6502(K.W++);Rg.B.h=Op6502(K.W)
|
||||
#define MC_Iy(Rg) K.W=Op6502(R->PC.W++); \
|
||||
Rg.B.l=Op6502(K.W++);Rg.B.h=Op6502(K.W); \
|
||||
Rg.W+=R->Y
|
||||
|
||||
/** Reading From Memory **************************************/
|
||||
/** These macros calculate address and read from it. **/
|
||||
/*************************************************************/
|
||||
#define MR_Ab(Rg) MC_Ab(J);Rg=Rd6502(J.W)
|
||||
#define MR_Im(Rg) Rg=Op6502(R->PC.W++)
|
||||
#define MR_Zp(Rg) MC_Zp(J);Rg=Rd6502(J.W)
|
||||
#define MR_Zx(Rg) MC_Zx(J);Rg=Rd6502(J.W)
|
||||
#define MR_Zy(Rg) MC_Zy(J);Rg=Rd6502(J.W)
|
||||
#define MR_Ax(Rg) MC_Ax(J);Rg=Rd6502(J.W)
|
||||
#define MR_Ay(Rg) MC_Ay(J);Rg=Rd6502(J.W)
|
||||
#define MR_Ix(Rg) MC_Ix(J);Rg=Rd6502(J.W)
|
||||
#define MR_Iy(Rg) MC_Iy(J);Rg=Rd6502(J.W)
|
||||
|
||||
/** Writing To Memory ****************************************/
|
||||
/** These macros calculate address and write to it. **/
|
||||
/*************************************************************/
|
||||
#define MW_Ab(Rg) MC_Ab(J);Wr6502(J.W,Rg)
|
||||
#define MW_Zp(Rg) MC_Zp(J);Wr6502(J.W,Rg)
|
||||
#define MW_Zx(Rg) MC_Zx(J);Wr6502(J.W,Rg)
|
||||
#define MW_Zy(Rg) MC_Zy(J);Wr6502(J.W,Rg)
|
||||
#define MW_Ax(Rg) MC_Ax(J);Wr6502(J.W,Rg)
|
||||
#define MW_Ay(Rg) MC_Ay(J);Wr6502(J.W,Rg)
|
||||
#define MW_Ix(Rg) MC_Ix(J);Wr6502(J.W,Rg)
|
||||
#define MW_Iy(Rg) MC_Iy(J);Wr6502(J.W,Rg)
|
||||
|
||||
/** Modifying Memory *****************************************/
|
||||
/** These macros calculate address and modify it. **/
|
||||
/*************************************************************/
|
||||
#define MM_Ab(Cmd) MC_Ab(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
|
||||
#define MM_Zp(Cmd) MC_Zp(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
|
||||
#define MM_Zx(Cmd) MC_Zx(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
|
||||
#define MM_Ax(Cmd) MC_Ax(J);I=Rd6502(J.W);Cmd(I);Wr6502(J.W,I)
|
||||
|
||||
/** Other Macros *********************************************/
|
||||
/** Calculating flags, stack, jumps, arithmetics, etc. **/
|
||||
/*************************************************************/
|
||||
#define M_FL(Rg) R->P=(R->P&~(Z_FLAG|N_FLAG))|ZNTable[Rg]
|
||||
#define M_LDWORD(Rg) Rg.B.l=Op6502(R->PC.W++);Rg.B.h=Op6502(R->PC.W++)
|
||||
|
||||
#define M_PUSH(Rg) Wr6502(0x0100|R->S,Rg);R->S--
|
||||
#define M_POP(Rg) R->S++;Rg=Op6502(0x0100|R->S)
|
||||
#define M_JR R->PC.W+=(offset)Op6502(R->PC.W)+1;R->ICount--
|
||||
|
||||
#ifdef NO_DECIMAL
|
||||
|
||||
#define M_ADC(Rg) \
|
||||
K.W=R->A+Rg+(R->P&C_FLAG); \
|
||||
R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
|
||||
R->P|=(~(R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
|
||||
(K.B.h? C_FLAG:0)|ZNTable[K.B.l]; \
|
||||
R->A=K.B.l
|
||||
|
||||
/* Warning! C_FLAG is inverted before SBC and after it */
|
||||
#define M_SBC(Rg) \
|
||||
K.W=R->A-Rg-(~R->P&C_FLAG); \
|
||||
R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
|
||||
R->P|=((R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
|
||||
(K.B.h? 0:C_FLAG)|ZNTable[K.B.l]; \
|
||||
R->A=K.B.l
|
||||
|
||||
#else /* NO_DECIMAL */
|
||||
|
||||
#define M_ADC(Rg) \
|
||||
if(R->P&D_FLAG) \
|
||||
{ \
|
||||
K.B.l=(R->A&0x0F)+(Rg&0x0F)+(R->P&C_FLAG); \
|
||||
if(K.B.l>9) K.B.l+=6; \
|
||||
K.B.h=(R->A>>4)+(Rg>>4)+(K.B.l>15? 1:0); \
|
||||
R->A=(K.B.l&0x0F)|(K.B.h<<4); \
|
||||
R->P=(R->P&~C_FLAG)|(K.B.h>15? C_FLAG:0); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
K.W=R->A+Rg+(R->P&C_FLAG); \
|
||||
R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
|
||||
R->P|=(~(R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
|
||||
(K.B.h? C_FLAG:0)|ZNTable[K.B.l]; \
|
||||
R->A=K.B.l; \
|
||||
}
|
||||
|
||||
/* Warning! C_FLAG is inverted before SBC and after it */
|
||||
#define M_SBC(Rg) \
|
||||
if(R->P&D_FLAG) \
|
||||
{ \
|
||||
K.B.l=(R->A&0x0F)-(Rg&0x0F)-(~R->P&C_FLAG); \
|
||||
if(K.B.l&0x10) K.B.l-=6; \
|
||||
K.B.h=(R->A>>4)-(Rg>>4)-((K.B.l&0x10)>>4); \
|
||||
if(K.B.h&0x10) K.B.h-=6; \
|
||||
R->A=(K.B.l&0x0F)|(K.B.h<<4); \
|
||||
R->P=(R->P&~C_FLAG)|(K.B.h>15? 0:C_FLAG); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
K.W=R->A-Rg-(~R->P&C_FLAG); \
|
||||
R->P&=~(N_FLAG|V_FLAG|Z_FLAG|C_FLAG); \
|
||||
R->P|=((R->A^Rg)&(R->A^K.B.l)&0x80? V_FLAG:0)| \
|
||||
(K.B.h? 0:C_FLAG)|ZNTable[K.B.l]; \
|
||||
R->A=K.B.l; \
|
||||
}
|
||||
|
||||
#endif /* NO_DECIMAL */
|
||||
|
||||
#define M_CMP(Rg1,Rg2) \
|
||||
K.W=Rg1-Rg2; \
|
||||
R->P&=~(N_FLAG|Z_FLAG|C_FLAG); \
|
||||
R->P|=ZNTable[K.B.l]|(K.B.h? 0:C_FLAG)
|
||||
#define M_BIT(Rg) \
|
||||
R->P&=~(N_FLAG|V_FLAG|Z_FLAG); \
|
||||
R->P|=(Rg&(N_FLAG|V_FLAG))|(Rg&R->A? 0:Z_FLAG)
|
||||
|
||||
#define M_AND(Rg) R->A&=Rg;M_FL(R->A)
|
||||
#define M_ORA(Rg) R->A|=Rg;M_FL(R->A)
|
||||
#define M_EOR(Rg) R->A^=Rg;M_FL(R->A)
|
||||
#define M_INC(Rg) Rg++;M_FL(Rg)
|
||||
#define M_DEC(Rg) Rg--;M_FL(Rg)
|
||||
|
||||
#define M_ASL(Rg) R->P&=~C_FLAG;R->P|=Rg>>7;Rg<<=1;M_FL(Rg)
|
||||
#define M_LSR(Rg) R->P&=~C_FLAG;R->P|=Rg&C_FLAG;Rg>>=1;M_FL(Rg)
|
||||
#define M_ROL(Rg) K.B.l=(Rg<<1)|(R->P&C_FLAG); \
|
||||
R->P&=~C_FLAG;R->P|=Rg>>7;Rg=K.B.l; \
|
||||
M_FL(Rg)
|
||||
#define M_ROR(Rg) K.B.l=(Rg>>1)|(R->P<<7); \
|
||||
R->P&=~C_FLAG;R->P|=Rg&C_FLAG;Rg=K.B.l; \
|
||||
M_FL(Rg)
|
||||
|
||||
/** Reset6502() **********************************************/
|
||||
/** This function can be used to reset the registers before **/
|
||||
/** starting execution with Run6502(). It sets registers to **/
|
||||
/** their initial values. **/
|
||||
/*************************************************************/
|
||||
void Reset6502(M6502 *R)
|
||||
{
|
||||
R->A=R->X=R->Y=0x00;
|
||||
R->P=Z_FLAG|R_FLAG;
|
||||
R->S=0xFF;
|
||||
R->PC.B.l=Rd6502(0xFFFC);
|
||||
R->PC.B.h=Rd6502(0xFFFD);
|
||||
R->ICount=R->IPeriod;
|
||||
R->IRequest=INT_NONE;
|
||||
R->AfterCLI=0;
|
||||
}
|
||||
|
||||
/** Exec6502() ***********************************************/
|
||||
/** This function will execute a single 6502 opcode. It **/
|
||||
/** will then return next PC, and current register values **/
|
||||
/** in R. **/
|
||||
/*************************************************************/
|
||||
word Exec6502(M6502 *R)
|
||||
{
|
||||
register pair J,K;
|
||||
register byte I;
|
||||
|
||||
I=Op6502(R->PC.W++);
|
||||
R->ICount-=Cycles[I];
|
||||
switch(I)
|
||||
{
|
||||
#include "Codes.h"
|
||||
}
|
||||
|
||||
/* We are done */
|
||||
return(R->PC.W);
|
||||
}
|
||||
|
||||
/** Int6502() ************************************************/
|
||||
/** This function will generate interrupt of a given type. **/
|
||||
/** INT_NMI will cause a non-maskable interrupt. INT_IRQ **/
|
||||
/** will cause a normal interrupt, unless I_FLAG set in R. **/
|
||||
/*************************************************************/
|
||||
void Int6502(M6502 *R,byte Type)
|
||||
{
|
||||
register pair J;
|
||||
|
||||
if((Type==INT_NMI)||((Type==INT_IRQ)&&!(R->P&I_FLAG)))
|
||||
{
|
||||
R->ICount-=7;
|
||||
M_PUSH(R->PC.B.h);
|
||||
M_PUSH(R->PC.B.l);
|
||||
M_PUSH(R->P&~B_FLAG);
|
||||
R->P&=~D_FLAG;
|
||||
if(R->IAutoReset&&(Type==R->IRequest)) R->IRequest=INT_NONE;
|
||||
if(Type==INT_NMI) J.W=0xFFFA; else { R->P|=I_FLAG;J.W=0xFFFE; }
|
||||
R->PC.B.l=Rd6502(J.W++);
|
||||
R->PC.B.h=Rd6502(J.W);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Run6502() ************************************************/
|
||||
/** This function will run 6502 code until Loop6502() call **/
|
||||
/** returns INT_QUIT. It will return the PC at which **/
|
||||
/** emulation stopped, and current register values in R. **/
|
||||
/*************************************************************/
|
||||
word Run6502(M6502 *R)
|
||||
{
|
||||
register pair J,K;
|
||||
register byte I;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
/* Turn tracing on when reached trap address */
|
||||
if(R->PC.W==R->Trap) R->Trace=1;
|
||||
/* Call single-step debugger, exit if requested */
|
||||
if(R->Trace)
|
||||
if(!Debug6502(R)) return(R->PC.W);
|
||||
#endif
|
||||
|
||||
I=Op6502(R->PC.W++);
|
||||
R->ICount-=Cycles[I];
|
||||
|
||||
//#ifdef DEBUG
|
||||
// pushop(I);
|
||||
//#endif
|
||||
|
||||
icount++;
|
||||
|
||||
switch(I)
|
||||
{
|
||||
#include "Codes.h"
|
||||
}
|
||||
|
||||
/* If cycle counter expired... */
|
||||
if(R->ICount<=0)
|
||||
{
|
||||
/* If we have come after CLI, get INT_? from IRequest */
|
||||
/* Otherwise, get it from the loop handler */
|
||||
if(R->AfterCLI)
|
||||
{
|
||||
I=R->IRequest; /* Get pending interrupt */
|
||||
R->ICount+=R->IBackup-1; /* Restore the ICount */
|
||||
R->AfterCLI=0; /* Done with AfterCLI state */
|
||||
}
|
||||
else
|
||||
{
|
||||
I=Loop6502(R); /* Call the periodic handler */
|
||||
R->ICount+=R->IPeriod; /* Reset the cycle counter */
|
||||
if(!I) I=R->IRequest; /* Realize pending interrupt */
|
||||
}
|
||||
|
||||
if(I==INT_QUIT) return(R->PC.W); /* Exit if INT_QUIT */
|
||||
if(I) Int6502(R,I); /* Interrupt if needed */
|
||||
}
|
||||
}
|
||||
|
||||
/* Execution stopped */
|
||||
return(R->PC.W);
|
||||
}
|
||||
148
src/corecpu/M6502.h
Executable file
148
src/corecpu/M6502.h
Executable file
@ -0,0 +1,148 @@
|
||||
/** M6502: portable 6502 emulator ****************************/
|
||||
/** **/
|
||||
/** M6502.h **/
|
||||
/** **/
|
||||
/** This file contains declarations relevant to emulation **/
|
||||
/** of 6502 CPU. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2002 **/
|
||||
/** Alex Krasivsky 1996 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
/*
|
||||
* $LastChangedDate: 2007-04-23 18:55:35 +0200 (lun, 23 avr 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/M6502.h $
|
||||
* $Revision: 45 $
|
||||
*/
|
||||
|
||||
#ifndef M6502_H
|
||||
#define M6502_H
|
||||
/* Loop6502() returns: */
|
||||
#define INT_NONE 0 /* No interrupt required */
|
||||
#define INT_IRQ 1 /* Standard IRQ interrupt */
|
||||
#define INT_NMI 2 /* Non-maskable interrupt */
|
||||
#define INT_QUIT 3 /* Exit the emulation */
|
||||
|
||||
/* 6502 status flags: */
|
||||
#define C_FLAG 0x01 /* 1: Carry occured */
|
||||
#define Z_FLAG 0x02 /* 1: Result is zero */
|
||||
#define I_FLAG 0x04 /* 1: Interrupts disabled */
|
||||
#define D_FLAG 0x08 /* 1: Decimal mode */
|
||||
#define B_FLAG 0x10 /* Break [0 on stk after int] */
|
||||
#define R_FLAG 0x20 /* Always 1 */
|
||||
#define V_FLAG 0x40 /* 1: Overflow occured */
|
||||
#define N_FLAG 0x80 /* 1: Result is negative */
|
||||
|
||||
/** Simple Datatypes *****************************************/
|
||||
/** NOTICE: sizeof(byte)=1 and sizeof(word)=2 **/
|
||||
/*************************************************************/
|
||||
#ifndef BYTE_TYPE_DEFINED
|
||||
#define BYTE_TYPE_DEFINED
|
||||
typedef unsigned char byte;
|
||||
#endif
|
||||
#ifndef WORD_TYPE_DEFINED
|
||||
#define WORD_TYPE_DEFINED
|
||||
typedef unsigned short word;
|
||||
#endif
|
||||
typedef signed char offset;
|
||||
|
||||
/** Structured Datatypes *************************************/
|
||||
/** NOTICE: #define LSB_FIRST for machines where least **/
|
||||
/** signifcant byte goes first. **/
|
||||
/*************************************************************/
|
||||
typedef union
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
struct { byte l,h; } B;
|
||||
#else
|
||||
struct { byte h,l; } B;
|
||||
#endif
|
||||
word W;
|
||||
} pair;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte A,P,X,Y,S; /* CPU registers and program counter */
|
||||
pair PC;
|
||||
|
||||
int IPeriod,ICount; /* Set IPeriod to number of CPU cycles */
|
||||
/* between calls to Loop6502() */
|
||||
byte IRequest; /* Set to the INT_IRQ when pending IRQ */
|
||||
byte AfterCLI; /* Private, don't touch */
|
||||
int IBackup; /* Private, don't touch */
|
||||
byte IAutoReset; /* Set to 1 to autom. reset IRequest */
|
||||
byte TrapBadOps; /* Set to 1 to warn of illegal opcodes */
|
||||
word Trap; /* Set Trap to address to trace from */
|
||||
byte Trace; /* Set Trace=1 to start tracing */
|
||||
void *User; /* Arbitrary user data (ID,RAM*,etc.) */
|
||||
} M6502;
|
||||
|
||||
/** Reset6502() **********************************************/
|
||||
/** This function can be used to reset the registers before **/
|
||||
/** starting execution with Run6502(). It sets registers to **/
|
||||
/** their initial values. **/
|
||||
/*************************************************************/
|
||||
void Reset6502(register M6502 *R);
|
||||
|
||||
/** Exec6502() ***********************************************/
|
||||
/** This function will execute a single 6502 opcode. It **/
|
||||
/** will then return next PC, and current register values **/
|
||||
/** in R. **/
|
||||
/*************************************************************/
|
||||
word Exec6502(register M6502 *R);
|
||||
|
||||
/** Int6502() ************************************************/
|
||||
/** This function will generate interrupt of a given type. **/
|
||||
/** INT_NMI will cause a non-maskable interrupt. INT_IRQ **/
|
||||
/** will cause a normal interrupt, unless I_FLAG set in R. **/
|
||||
/*************************************************************/
|
||||
void Int6502(register M6502 *R,register byte Type);
|
||||
|
||||
/** Run6502() ************************************************/
|
||||
/** This function will run 6502 code until Loop6502() call **/
|
||||
/** returns INT_QUIT. It will return the PC at which **/
|
||||
/** emulation stopped, and current register values in R. **/
|
||||
/*************************************************************/
|
||||
word Run6502(register M6502 *R);
|
||||
|
||||
/** Rd6502()/Wr6502/Op6502() *********************************/
|
||||
/** These functions are called when access to RAM occurs. **/
|
||||
/** They allow to control memory access. Op6502 is the same **/
|
||||
/** as Rd6502, but used to read *opcodes* only, when many **/
|
||||
/** checks can be skipped to make it fast. It is only **/
|
||||
/** required if there is a #define FAST_RDOP. **/
|
||||
/************************************ TO BE WRITTEN BY USER **/
|
||||
void Wr6502(register word Addr,register byte Value);
|
||||
byte Rd6502(register word Addr);
|
||||
byte Op6502(register word Addr);
|
||||
|
||||
/** Debug6502() **********************************************/
|
||||
/** This function should exist if DEBUG is #defined. When **/
|
||||
/** Trace!=0, it is called after each command executed by **/
|
||||
/** the CPU, and given the 6502 registers. Emulation exits **/
|
||||
/** if Debug6502() returns 0. **/
|
||||
/*************************************************************/
|
||||
byte Debug6502(register M6502 *R);
|
||||
|
||||
/** Loop6502() ***********************************************/
|
||||
/** 6502 emulation calls this function periodically to **/
|
||||
/** check if the system hardware requires any interrupts. **/
|
||||
/** This function must return one of following values: **/
|
||||
/** INT_NONE, INT_IRQ, INT_NMI, or INT_QUIT to exit the **/
|
||||
/** emulation loop. **/
|
||||
/************************************ TO BE WRITTEN BY USER **/
|
||||
byte Loop6502(register M6502 *R);
|
||||
|
||||
/** Patch6502() **********************************************/
|
||||
/** Emulation calls this function when it encounters an **/
|
||||
/** unknown opcode. This can be used to patch the code to **/
|
||||
/** emulate BIOS calls, such as disk and tape access. The **/
|
||||
/** function should return 1 if the exception was handled, **/
|
||||
/** or 0 if the opcode was truly illegal. **/
|
||||
/************************************ TO BE WRITTEN BY USER **/
|
||||
byte Patch6502(register byte Op,register M6502 *R);
|
||||
|
||||
#endif /* M6502_H */
|
||||
71
src/corecpu/Tables.h
Executable file
71
src/corecpu/Tables.h
Executable file
@ -0,0 +1,71 @@
|
||||
/** M6502: portable 6502 emulator ****************************/
|
||||
/** **/
|
||||
/** Tables.h **/
|
||||
/** **/
|
||||
/** This file contains tables of used by 6502 emulation to **/
|
||||
/** compute NEGATIVE and ZERO flags. There are also timing **/
|
||||
/** tables for 6502 opcodes. This file is included from **/
|
||||
/** 6502.c. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2002 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
/*
|
||||
* $LastChangedDate: 2007-05-24 15:07:13 +0200 (jeu, 24 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/Tables.h $
|
||||
* $Revision: 52 $
|
||||
*/
|
||||
|
||||
static byte Cycles[256] =
|
||||
{
|
||||
7, 6, 2, 1, 5, 3, 5, 5, 3, 2, 2, 1, 6, 4, 6, 2,
|
||||
2, 5, 5, 1, 5, 4, 6, 5, 2, 4, 2, 1, 6, 4, 6, 2,
|
||||
6, 6, 2, 1, 3, 3, 5, 5, 4, 2, 2, 1, 4, 4, 6, 2,
|
||||
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 2, 1, 4, 4, 6, 2,
|
||||
6, 6, 2, 1, 3, 3, 5, 5, 3, 2, 2, 1, 3, 4, 6, 2,
|
||||
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 3, 1, 8, 4, 6, 2,
|
||||
6, 6, 2, 1, 3, 3, 5, 5, 4, 2, 2, 1, 6, 4, 6, 2,
|
||||
2, 5, 5, 1, 4, 4, 6, 5, 5, 4, 4, 1, 6, 4, 6, 2,
|
||||
3, 6, 2, 1, 3, 3, 3, 5, 2, 2, 2, 1, 4, 4, 4, 2,
|
||||
2, 6, 5, 1, 4, 4, 4, 5, 2, 5, 2, 1, 4, 5, 5, 2,
|
||||
2, 6, 2, 1, 3, 3, 3, 5, 2, 2, 2, 1, 4, 4, 4, 2,
|
||||
2, 5, 5, 1, 4, 4, 4, 5, 2, 4, 2, 1, 4, 4, 4, 2,
|
||||
2, 6, 2, 1, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 2,
|
||||
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 3, 2, 4, 4, 6, 2,
|
||||
2, 6, 2, 1, 3, 3, 5, 5, 2, 2, 2, 1, 4, 4, 6, 2,
|
||||
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 4, 1, 4, 4, 6, 2
|
||||
};
|
||||
|
||||
|
||||
byte ZNTable[256] =
|
||||
{
|
||||
|
||||
Z_FLAG, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG, N_FLAG,
|
||||
};
|
||||
|
||||
1038
src/include/MIDIFreq.h
Normal file
1038
src/include/MIDIFreq.h
Normal file
File diff suppressed because it is too large
Load Diff
39
src/include/NESCarts.h
Executable file
39
src/include/NESCarts.h
Executable file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Cart manager - The TI-NESulator Project
|
||||
* NESCart.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/NESCarts.h $
|
||||
* $Revision: 39 $
|
||||
*/
|
||||
|
||||
#ifndef NESCARTS_H
|
||||
#define NESCARTS_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define iNES_MIRROR 0x01
|
||||
#define iNES_BATTERY 0x02
|
||||
#define iNES_TRAINER 0x04
|
||||
#define iNES_4SCREEN 0x08
|
||||
|
||||
typedef struct NesCart_
|
||||
{
|
||||
unsigned long PROMSize, /* Size of PROM */
|
||||
VROMSize; /* Size of VROM */
|
||||
char MapperID; /* Mapper Type */
|
||||
byte Flags;
|
||||
char *FileName;
|
||||
byte *File; /* Pointer on the file in memory */
|
||||
byte *PROMBanks; /* Pointer on the first PROM */
|
||||
byte *VROMBanks; /* Pointer on the first VROM */
|
||||
} NesCart;
|
||||
|
||||
void DumpCartProperties();
|
||||
int LoadCart(const char *filename, NesCart * cart);
|
||||
|
||||
#endif
|
||||
232
src/include/Sound.h
Normal file
232
src/include/Sound.h
Normal file
@ -0,0 +1,232 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** Sound.h **/
|
||||
/** **/
|
||||
/** This file defines standard sound generation API and **/
|
||||
/** functions needed to log soundtrack into a MIDI file. **/
|
||||
/** See Sound.c and the sound drivers for the code. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2007 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
|
||||
#ifndef SOUND_H
|
||||
#define SOUND_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* SetSound() arguments: */
|
||||
#define SND_MELODIC 0 /* Melodic sound (default) */
|
||||
#define SND_RECTANGLE 0 /* Rectangular wave */
|
||||
#define SND_QS_DU0 5
|
||||
#define SND_QS_DU1 6
|
||||
#define SND_QS_DU2 7
|
||||
#define SND_QS_DU3 8
|
||||
#define SND_TRIANGLE 1 /* Triangular wave (1/2 rect.)*/
|
||||
#define SND_NOISE 2 /* White noise */
|
||||
#define SND_PERIODIC 3 /* Periodic noise (not im-ed) */
|
||||
#define SND_WAVE 4 /* Wave sound set by SetWave()*/
|
||||
#define SND_MIDI 0x100 /* MIDI instrument (ORable) */
|
||||
|
||||
/* Drum() arguments: */
|
||||
#define DRM_CLICK 0 /* Click (default) */
|
||||
#define DRM_MIDI 0x100 /* MIDI drum (ORable) */
|
||||
|
||||
/* MIDI characteristics: */
|
||||
#define MIDI_CHANNELS 16 /* Number of MIDI channels */
|
||||
#define MIDI_MINFREQ 9 /* Min MIDI frequency (Hz) */
|
||||
#define MIDI_MAXFREQ 12285 /* Max MIDI frequency (Hz) */
|
||||
#define MIDI_DIVISIONS 1000 /* Number of ticks per second */
|
||||
|
||||
/* MIDILogging() arguments: */
|
||||
#define MIDI_OFF 0 /* Turn MIDI logging off */
|
||||
#define MIDI_ON 1 /* Turn MIDI logging on */
|
||||
#define MIDI_TOGGLE 2 /* Toggle MIDI logging */
|
||||
#define MIDI_QUERY 3 /* Query MIDI logging status */
|
||||
|
||||
/** TrashSound() *********************************************/
|
||||
/** Shut down sound driver. Each driver implements its own **/
|
||||
/** TrashSound() function. **/
|
||||
/*************************************************************/
|
||||
void TrashSound(void);
|
||||
|
||||
/** Sound() **************************************************/
|
||||
/** Generate sound of given frequency (Hz) and volume **/
|
||||
/** (0..255) via given channel. Setting Freq=0 or Volume=0 **/
|
||||
/** turns sound off. **/
|
||||
/*************************************************************/
|
||||
void Sound(int Channel,int Freq,int Volume);
|
||||
|
||||
/** Drum() ***************************************************/
|
||||
/** Hit a drum of given type with given force (0..255). **/
|
||||
/** MIDI drums can be used by ORing their numbers with **/
|
||||
/** SND_MIDI. **/
|
||||
/*************************************************************/
|
||||
void Drum(int Type,int Force);
|
||||
|
||||
/** SetSound() ***********************************************/
|
||||
/** Set sound type at a given channel. MIDI instruments can **/
|
||||
/** be set directly by ORing their numbers with SND_MIDI. **/
|
||||
/*************************************************************/
|
||||
void SetSound(int Channel,int NewType);
|
||||
|
||||
/** SetChannels() ********************************************/
|
||||
/** Set master volume (0..255) and switch channels on/off. **/
|
||||
/** Each channel N has corresponding bit 2^N in Switch. Set **/
|
||||
/** or reset this bit to turn the channel on or off. **/
|
||||
/*************************************************************/
|
||||
void SetChannels(int Volume,int Switch);
|
||||
|
||||
/** SetWave() ************************************************/
|
||||
/** Set waveform for a given channel. The channel will be **/
|
||||
/** marked with sound type SND_WAVE. Set Rate=0 if you want **/
|
||||
/** waveform to be an instrument or set it to the waveform **/
|
||||
/** own playback rate. **/
|
||||
/*************************************************************/
|
||||
void SetWave(int Channel,const signed char *Data,int Length,int Rate);
|
||||
|
||||
/** GetWave() ************************************************/
|
||||
/** Get current read position for the buffer set with the **/
|
||||
/** SetWave() call. Returns 0 if no buffer has been set, or **/
|
||||
/** if there is no playrate set (i.e. wave is instrument). **/
|
||||
/*************************************************************/
|
||||
const signed char *GetWave(int Channel);
|
||||
|
||||
/** InitMIDI() ***********************************************/
|
||||
/** Initialize soundtrack logging into MIDI file FileName. **/
|
||||
/** Repeated calls to InitMIDI() will close current MIDI **/
|
||||
/** file and continue logging into a new one. **/
|
||||
/*************************************************************/
|
||||
void InitMIDI(const char *FileName);
|
||||
|
||||
/** TrashMIDI() **********************************************/
|
||||
/** Finish logging soundtrack and close the MIDI file. **/
|
||||
/*************************************************************/
|
||||
void TrashMIDI(void);
|
||||
|
||||
/** MIDILogging() ********************************************/
|
||||
/** Turn soundtrack logging on/off and return its current **/
|
||||
/** status. Possible values of Switch are MIDI_OFF (turn **/
|
||||
/** logging off), MIDI_ON (turn logging on), MIDI_TOGGLE **/
|
||||
/** (toggle logging), and MIDI_QUERY (just return current **/
|
||||
/** state of logging). **/
|
||||
/*************************************************************/
|
||||
int MIDILogging(int Switch);
|
||||
|
||||
/** MIDITicks() **********************************************/
|
||||
/** Log N 1ms MIDI ticks. **/
|
||||
/*************************************************************/
|
||||
void MIDITicks(int N);
|
||||
|
||||
//#ifdef UNIX
|
||||
#define SND_CHANNELS 16 /* Number of channels */
|
||||
#define SND_SAMPLESIZE 256 /* Max. SetWave() sample size */
|
||||
#define SND_BUFSIZE 256 /* Buffer size, <= 2^SND_BITS */
|
||||
#define SND_BITS 8 /* Number of bits in a fragment */
|
||||
#define SND_BUFFERS 64 /* Number of fragments, >= 2 */
|
||||
/* Bigger value results in better behaviour on loaded */
|
||||
/* but output gets more delayed. */
|
||||
|
||||
/** InitSound() **********************************************/
|
||||
/** Initialize Unix sound driver with given synthesis rate. **/
|
||||
/** Returns Rate on success, 0 otherwise. Pass Rate=0 to **/
|
||||
/** skip initialization and be silent. Pass Verbose!=0 to **/
|
||||
/** see initialization messages. **/
|
||||
/*************************************************************/
|
||||
#warning You Suck !
|
||||
int InitSound(int Rate,int Verbose);
|
||||
|
||||
/** StopSound() **********************************************/
|
||||
/** Temporarily suspend sound. **/
|
||||
/*************************************************************/
|
||||
void StopSound(void);
|
||||
|
||||
/** ResumeSound() ********************************************/
|
||||
/** Resume sound after StopSound(). **/
|
||||
/*************************************************************/
|
||||
void ResumeSound(void);
|
||||
//#endif /* UNIX */
|
||||
|
||||
#ifdef MSDOS
|
||||
#define SND_CHANNELS 16 /* Number of sound channels */
|
||||
#define OPL_CHANNELS 7 /* Number of Adlib channels */
|
||||
#define SND_SAMPLESIZE 256 /* Max. SetWave() sample size */
|
||||
#define SND_BUFSIZE 512 /* Buffer size for DMA */
|
||||
#define SND_MAXDELAY 10 /* Maximal sound delay 1/n s */
|
||||
|
||||
/** InitSound() **********************************************/
|
||||
/** Initialize sound. Returns Rate on success, 0 otherwise. **/
|
||||
/** Rate=0 to skip initialization (will be silent). **/
|
||||
/*************************************************************/
|
||||
int InitSound(unsigned int Rate,unsigned int Latency);
|
||||
#endif /* MSDOS */
|
||||
|
||||
#ifdef WINDOWS
|
||||
#define SND_CHANNELS 16 /* Number of channels */
|
||||
#define SND_SAMPLESIZE 256 /* Max. SetWave() sample size */
|
||||
#define SND_BUFSIZE 512 /* Size of a wave buffer */
|
||||
#define SND_BUFFERS 32 /* Number of wave buffers */
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
/** InitSound() **********************************************/
|
||||
/** Initialize Windows sound driver with given synthesis **/
|
||||
/** rate. Returns Rate on success, 0 otherwise. Pass Rate=0 **/
|
||||
/** to skip initialization and be silent. Pass Rate=1 to **/
|
||||
/** use MIDI (midiOut). Pass Rate=8192..44100 to use wave **/
|
||||
/** synthesis (waveOut). Number of wave synthesis buffers **/
|
||||
/** must be in 2..SND_BUFFERS range. **/
|
||||
/*************************************************************/
|
||||
unsigned int InitSound(unsigned int Rate,unsigned int Delay);
|
||||
#endif /* WINDOWS */
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
#ifndef MSDOS
|
||||
#ifndef WINDOWS
|
||||
#ifndef UNIX
|
||||
#define SND_CHANNELS MIDI_CHANNELS /* Default number */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** InitSound() **********************************************/
|
||||
/** Initialize Series60 sound driver with given synthesis **/
|
||||
/** rate. Returns Rate on success, 0 otherwise. Pass Rate=0 **/
|
||||
/** to skip initialization and be silent. **/
|
||||
/*************************************************************/
|
||||
unsigned int InitSound(unsigned int Rate,unsigned int Delay);
|
||||
#endif
|
||||
|
||||
/** RenderAudio() ********************************************/
|
||||
/** Render given number of melodic sound samples. Returns **/
|
||||
/** number of samples actually rendered. **/
|
||||
/*************************************************************/
|
||||
unsigned int RenderAudio(unsigned int Samples);
|
||||
|
||||
/** SndDriver ************************************************/
|
||||
/** Each sound driver should fill this structure with **/
|
||||
/** pointers to hardware-dependent handlers. This has to be **/
|
||||
/** done inside the InitSound() function. **/
|
||||
/*************************************************************/
|
||||
struct SndDriverStruct
|
||||
{
|
||||
void (*SetSound)(int Channel,int NewType);
|
||||
void (*Drum)(int Type,int Force);
|
||||
void (*SetChannels)(int Volume,int Switch);
|
||||
void (*Sound)(int Channel,int NewFreq,int NewVolume);
|
||||
void (*SetWave)(int Channel,const signed char *Data,int Length,int Freq);
|
||||
const signed char *(*GetWave)(int Channel);
|
||||
};
|
||||
extern struct SndDriverStruct SndDriver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SOUND_H */
|
||||
60
src/include/mappers/manager.h
Executable file
60
src/include/mappers/manager.h
Executable file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Mappers manager & facilities - The TI-NESulator Project
|
||||
* mappers.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate$
|
||||
* $Author$
|
||||
* $HeadURL$
|
||||
* $Revision$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAPPERS_H
|
||||
#define MAPPERS_H
|
||||
|
||||
#include <types.h>
|
||||
#include <stdio.h>
|
||||
#include <NESCarts.h>
|
||||
|
||||
typedef int (*MapperInit) (NesCart * cart);
|
||||
typedef int (*MapperWriteHook) (register unsigned short Addr,
|
||||
register unsigned char Value);
|
||||
typedef int (*MapperIRQ) (int cycledone);
|
||||
typedef void (*MapperDump) ();
|
||||
|
||||
#ifdef __TINES_MAPPERS__
|
||||
|
||||
extern NesCart *Cart;
|
||||
|
||||
/* Available functions for mappers */
|
||||
#define GETLAST08KBANK(c) ((c->PROMSize>>13)-1)
|
||||
#define GETLAST16KBANK(c) ((c->PROMSize>>14)-1)
|
||||
#define GETLAST32KBANK(c) ((c->PROMSize>>15)-1)
|
||||
|
||||
void map_sram(); /* Map SRAM */
|
||||
void unmap_sram(); /* Unmap SRAM */
|
||||
|
||||
void set_vrom_bank_1k(unsigned short addr,int slot);
|
||||
void set_vrom_bank_2k(unsigned short addr,int slot);
|
||||
void set_vrom_bank_4k(unsigned short addr,int slot);
|
||||
void set_vrom_bank_8k(unsigned short addr, int slot);
|
||||
|
||||
void set_prom_bank_8k(unsigned short addr,int slot);
|
||||
void set_prom_bank_16k(unsigned short addr,int slot);
|
||||
void set_prom_bank_32k(unsigned short addr,int slot);
|
||||
|
||||
#else /* __TINES_MAPPERS__ */
|
||||
|
||||
/* Available functions outside of mappers */
|
||||
|
||||
void mapper_list ();
|
||||
int mapper_init (NesCart *cart);
|
||||
extern int (*mapper_irqloop) (int cyclodone);
|
||||
extern void (*mapper_dump) (FILE *fp);
|
||||
|
||||
#endif /* __TINES_MAPPERS__ */
|
||||
|
||||
#endif
|
||||
68
src/include/memory/manager.h
Executable file
68
src/include/memory/manager.h
Executable file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 6502 Memory manager - The TI-NESulator Project
|
||||
* memory.h - Taken from the Quick6502 project
|
||||
*
|
||||
* Created by Manoël Trapier on 18/09/06.
|
||||
* Copyright 2003-2007 986 Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-05 16:30:20 +0200 (jeu, 05 avr 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/memory.h $
|
||||
* $Revision: 31 $
|
||||
*
|
||||
*/
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define ATTR_PAGE_HAVE_RDHOOK 0x20
|
||||
#define ATTR_PAGE_HAVE_WRHOOK 0x10
|
||||
#define ATTR_PAGE_WRITEABLE 0x08
|
||||
#define ATTR_PAGE_READABLE 0x04
|
||||
#define ATTR_PAGE_GHOST 0x02
|
||||
#define ATTR_PAGE_MAPPED 0x01
|
||||
|
||||
typedef byte (*func_rdhook)(byte /* addr */);
|
||||
typedef void (*func_wrhook)(byte addr, byte data);
|
||||
|
||||
/* Functions to manage pages data */
|
||||
void set_page_ptr(byte page, byte *ptr);
|
||||
void set_page_ptr_1k(byte page, byte *ptr);
|
||||
void set_page_ptr_2k(byte page, byte *ptr);
|
||||
void set_page_ptr_4k(byte page, byte *ptr);
|
||||
void set_page_ptr_8k(byte page, byte *ptr);
|
||||
void set_page_ptr_16k(byte page, byte *ptr);
|
||||
void set_page_ptr_32k(byte page, byte *ptr);
|
||||
|
||||
byte *get_page_ptr(byte page);
|
||||
|
||||
|
||||
/* Functions to set pages attributes */
|
||||
|
||||
void set_page_rd_hook(byte page, func_rdhook func);
|
||||
|
||||
void set_page_wr_hook(byte page, func_wrhook func);
|
||||
|
||||
void set_page_readable(byte page, bool value);
|
||||
|
||||
void set_page_writeable(byte page, bool value);
|
||||
|
||||
void set_page_ghost(byte page, bool value, byte ghost);
|
||||
|
||||
byte get_page_attributes(byte page);
|
||||
|
||||
func_rdhook get_page_rdhook(byte page);
|
||||
|
||||
func_wrhook get_page_wrhook(byte page);
|
||||
|
||||
/* Generalist functions */
|
||||
|
||||
void InitMemory();
|
||||
|
||||
byte ReadMemory(byte page, byte addr);
|
||||
void WriteMemory(byte page, byte addr, byte value);
|
||||
|
||||
void DumpMemoryState();
|
||||
|
||||
#endif
|
||||
36
src/include/paddle.h
Executable file
36
src/include/paddle.h
Executable file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Paddle manager - The TI-NESulator Project
|
||||
* paddle.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/paddle.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PADDLE_H
|
||||
#define PADDLE_H
|
||||
|
||||
typedef struct Paddle_
|
||||
{
|
||||
|
||||
unsigned char Bit;
|
||||
|
||||
unsigned char LastWrite;
|
||||
|
||||
} Paddle;
|
||||
|
||||
|
||||
unsigned char ReadPaddle(Paddle * pdl);
|
||||
|
||||
|
||||
void InitPaddle(Paddle * pdl);
|
||||
|
||||
void WritePaddle(Paddle * pdl, unsigned char val);
|
||||
|
||||
|
||||
#endif
|
||||
261
src/include/palette.h
Normal file
261
src/include/palette.h
Normal file
@ -0,0 +1,261 @@
|
||||
/* Generated data file from file 'stdin' */
|
||||
|
||||
|
||||
PALETTE basicPalette = {
|
||||
{ 0x1E, 0x1E, 0x1E, 0x07 },
|
||||
{ 0x03, 0x09, 0x28, 0xB7 },
|
||||
{ 0x0A, 0x04, 0x2B, 0x0D },
|
||||
{ 0x17, 0x02, 0x28, 0x00 },
|
||||
{ 0x22, 0x00, 0x1D, 0xB7 },
|
||||
{ 0x24, 0x01, 0x0A, 0xB7 },
|
||||
{ 0x24, 0x04, 0x02, 0xB7 },
|
||||
{ 0x1B, 0x09, 0x01, 0xB7 },
|
||||
{ 0x11, 0x10, 0x01, 0x00 },
|
||||
{ 0x05, 0x15, 0x01, 0x00 },
|
||||
{ 0x01, 0x17, 0x02, 0xB7 },
|
||||
{ 0x00, 0x14, 0x0B, 0xBF },
|
||||
{ 0x01, 0x11, 0x1B, 0xBF },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x2F, 0x30, 0x2F, 0xB7 },
|
||||
{ 0x05, 0x1A, 0x37, 0xBF },
|
||||
{ 0x12, 0x10, 0x3B, 0xBF },
|
||||
{ 0x23, 0x09, 0x38, 0xB7 },
|
||||
{ 0x31, 0x06, 0x2E, 0xBF },
|
||||
{ 0x35, 0x08, 0x18, 0xB7 },
|
||||
{ 0x35, 0x0D, 0x08, 0x00 },
|
||||
{ 0x2D, 0x16, 0x03, 0xB7 },
|
||||
{ 0x22, 0x1E, 0x01, 0x00 },
|
||||
{ 0x0E, 0x24, 0x01, 0x00 },
|
||||
{ 0x05, 0x26, 0x06, 0x00 },
|
||||
{ 0x02, 0x26, 0x16, 0xB7 },
|
||||
{ 0x02, 0x22, 0x2A, 0xBF },
|
||||
{ 0x0B, 0x0B, 0x0B, 0xBF },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x3D, 0x3D, 0x3E, 0x00 },
|
||||
{ 0x12, 0x2C, 0x3E, 0xB7 },
|
||||
{ 0x22, 0x25, 0x3F, 0xB7 },
|
||||
{ 0x30, 0x1E, 0x3E, 0xB7 },
|
||||
{ 0x3A, 0x1B, 0x3B, 0xBF },
|
||||
{ 0x3D, 0x1D, 0x2E, 0xB7 },
|
||||
{ 0x3D, 0x20, 0x1B, 0xB7 },
|
||||
{ 0x3B, 0x28, 0x11, 0x07 },
|
||||
{ 0x35, 0x30, 0x08, 0x01 },
|
||||
{ 0x26, 0x35, 0x08, 0x00 },
|
||||
{ 0x14, 0x37, 0x11, 0x00 },
|
||||
{ 0x0F, 0x37, 0x25, 0x00 },
|
||||
{ 0x0A, 0x36, 0x37, 0xB7 },
|
||||
{ 0x18, 0x19, 0x19, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x3E, 0x3E, 0x3E, 0xB7 },
|
||||
{ 0x2D, 0x37, 0x3E, 0xB7 },
|
||||
{ 0x33, 0x34, 0x3F, 0x10 },
|
||||
{ 0x37, 0x31, 0x3E, 0x00 },
|
||||
{ 0x3C, 0x30, 0x3D, 0x00 },
|
||||
{ 0x3D, 0x30, 0x38, 0x00 },
|
||||
{ 0x3D, 0x33, 0x30, 0x00 },
|
||||
{ 0x3D, 0x36, 0x2B, 0x00 },
|
||||
{ 0x3B, 0x39, 0x26, 0x00 },
|
||||
{ 0x34, 0x3B, 0x27, 0x00 },
|
||||
{ 0x2E, 0x3C, 0x2D, 0x00 },
|
||||
{ 0x2C, 0x3C, 0x36, 0x00 },
|
||||
{ 0x29, 0x3C, 0x3C, 0x00 },
|
||||
{ 0x32, 0x31, 0x32, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x1E, 0x1E, 0x1E, 0xB7 },
|
||||
{ 0x03, 0x09, 0x28, 0xB7 },
|
||||
{ 0x0A, 0x04, 0x2B, 0xBF },
|
||||
{ 0x17, 0x02, 0x28, 0xB7 },
|
||||
{ 0x22, 0x00, 0x1D, 0xB7 },
|
||||
{ 0x24, 0x01, 0x0A, 0xB7 },
|
||||
{ 0x24, 0x04, 0x02, 0x00 },
|
||||
{ 0x1B, 0x09, 0x01, 0x00 },
|
||||
{ 0x11, 0x10, 0x01, 0x00 },
|
||||
{ 0x05, 0x15, 0x01, 0xB7 },
|
||||
{ 0x01, 0x17, 0x02, 0x00 },
|
||||
{ 0x00, 0x14, 0x0B, 0xB7 },
|
||||
{ 0x01, 0x11, 0x1B, 0x50 },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x2F, 0x30, 0x2F, 0xBF },
|
||||
{ 0x05, 0x1A, 0x37, 0xB7 },
|
||||
{ 0x12, 0x10, 0x3B, 0xB7 },
|
||||
{ 0x23, 0x09, 0x38, 0x20 },
|
||||
{ 0x31, 0x06, 0x2E, 0xBF },
|
||||
{ 0x35, 0x08, 0x18, 0xB7 },
|
||||
{ 0x35, 0x0D, 0x08, 0xBF },
|
||||
{ 0x2D, 0x16, 0x03, 0xBF },
|
||||
{ 0x22, 0x1E, 0x01, 0xB7 },
|
||||
{ 0x0E, 0x24, 0x01, 0xBF },
|
||||
{ 0x05, 0x26, 0x06, 0xB7 },
|
||||
{ 0x02, 0x26, 0x16, 0xBF },
|
||||
{ 0x02, 0x22, 0x2A, 0xBF },
|
||||
{ 0x0B, 0x0B, 0x0B, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x3D, 0x3D, 0x3E, 0xBF },
|
||||
{ 0x12, 0x2C, 0x3E, 0x53 },
|
||||
{ 0x22, 0x25, 0x3F, 0x54 },
|
||||
{ 0x30, 0x1E, 0x3E, 0x46 },
|
||||
{ 0x3A, 0x1B, 0x3B, 0x31 },
|
||||
{ 0x3D, 0x1D, 0x2E, 0x3A },
|
||||
{ 0x3D, 0x20, 0x1B, 0x32 },
|
||||
{ 0x3B, 0x28, 0x11, 0x54 },
|
||||
{ 0x35, 0x30, 0x08, 0x30 },
|
||||
{ 0x26, 0x35, 0x08, 0x00 },
|
||||
{ 0x14, 0x37, 0x11, 0x00 },
|
||||
{ 0x0F, 0x37, 0x25, 0x00 },
|
||||
{ 0x0A, 0x36, 0x37, 0x00 },
|
||||
{ 0x18, 0x19, 0x19, 0x00 },
|
||||
{ 0x01, 0x01, 0x01, 0x00 },
|
||||
{ 0x01, 0x01, 0x01, 0x00 },
|
||||
{ 0x3E, 0x3E, 0x3E, 0x00 },
|
||||
{ 0x2D, 0x37, 0x3E, 0x00 },
|
||||
{ 0x33, 0x34, 0x3F, 0x00 },
|
||||
{ 0x37, 0x31, 0x3E, 0x00 },
|
||||
{ 0x3C, 0x30, 0x3D, 0x00 },
|
||||
{ 0x3D, 0x30, 0x38, 0x00 },
|
||||
{ 0x3D, 0x33, 0x30, 0xB7 },
|
||||
{ 0x3D, 0x36, 0x2B, 0xB7 },
|
||||
{ 0x3B, 0x39, 0x26, 0x00 },
|
||||
{ 0x34, 0x3B, 0x27, 0xBF },
|
||||
{ 0x2E, 0x3C, 0x2D, 0xB7 },
|
||||
{ 0x2C, 0x3C, 0x36, 0xB7 },
|
||||
{ 0x29, 0x3C, 0x3C, 0xB7 },
|
||||
{ 0x32, 0x31, 0x32, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x1E, 0x1E, 0x1E, 0x07 },
|
||||
{ 0x03, 0x09, 0x28, 0xB7 },
|
||||
{ 0x0A, 0x04, 0x2B, 0x0D },
|
||||
{ 0x17, 0x02, 0x28, 0x00 },
|
||||
{ 0x22, 0x00, 0x1D, 0xB7 },
|
||||
{ 0x24, 0x01, 0x0A, 0xB7 },
|
||||
{ 0x24, 0x04, 0x02, 0xB7 },
|
||||
{ 0x1B, 0x09, 0x01, 0xB7 },
|
||||
{ 0x11, 0x10, 0x01, 0x00 },
|
||||
{ 0x05, 0x15, 0x01, 0x00 },
|
||||
{ 0x01, 0x17, 0x02, 0xB7 },
|
||||
{ 0x00, 0x14, 0x0B, 0x00 },
|
||||
{ 0x01, 0x11, 0x1B, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x2F, 0x30, 0x2F, 0xB7 },
|
||||
{ 0x05, 0x1A, 0x37, 0xBF },
|
||||
{ 0x12, 0x10, 0x3B, 0xB7 },
|
||||
{ 0x23, 0x09, 0x38, 0xB7 },
|
||||
{ 0x31, 0x06, 0x2E, 0x00 },
|
||||
{ 0x35, 0x08, 0x18, 0xBF },
|
||||
{ 0x35, 0x0D, 0x08, 0xB7 },
|
||||
{ 0x2D, 0x16, 0x03, 0xB7 },
|
||||
{ 0x22, 0x1E, 0x01, 0xB7 },
|
||||
{ 0x0E, 0x24, 0x01, 0x00 },
|
||||
{ 0x05, 0x26, 0x06, 0x00 },
|
||||
{ 0x02, 0x26, 0x16, 0xB7 },
|
||||
{ 0x02, 0x22, 0x2A, 0x06 },
|
||||
{ 0x0B, 0x0B, 0x0B, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x3D, 0x3D, 0x3E, 0xB7 },
|
||||
{ 0x12, 0x2C, 0x3E, 0xB7 },
|
||||
{ 0x22, 0x25, 0x3F, 0xB7 },
|
||||
{ 0x30, 0x1E, 0x3E, 0xB7 },
|
||||
{ 0x3A, 0x1B, 0x3B, 0x00 },
|
||||
{ 0x3D, 0x1D, 0x2E, 0x00 },
|
||||
{ 0x3D, 0x20, 0x1B, 0xB7 },
|
||||
{ 0x3B, 0x28, 0x11, 0xB7 },
|
||||
{ 0x35, 0x30, 0x08, 0x03 },
|
||||
{ 0x26, 0x35, 0x08, 0xB7 },
|
||||
{ 0x14, 0x37, 0x11, 0xBF },
|
||||
{ 0x0F, 0x37, 0x25, 0x00 },
|
||||
{ 0x0A, 0x36, 0x37, 0xB7 },
|
||||
{ 0x18, 0x19, 0x19, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x3E, 0x3E, 0x3E, 0x00 },
|
||||
{ 0x2D, 0x37, 0x3E, 0x00 },
|
||||
{ 0x33, 0x34, 0x3F, 0xB7 },
|
||||
{ 0x37, 0x31, 0x3E, 0xB7 },
|
||||
{ 0x3C, 0x30, 0x3D, 0x00 },
|
||||
{ 0x3D, 0x30, 0x38, 0x00 },
|
||||
{ 0x3D, 0x33, 0x30, 0xB7 },
|
||||
{ 0x3D, 0x36, 0x2B, 0xB7 },
|
||||
{ 0x3B, 0x39, 0x26, 0xB7 },
|
||||
{ 0x34, 0x3B, 0x27, 0xBF },
|
||||
{ 0x2E, 0x3C, 0x2D, 0xBF },
|
||||
{ 0x2C, 0x3C, 0x36, 0xB7 },
|
||||
{ 0x29, 0x3C, 0x3C, 0xBF },
|
||||
{ 0x32, 0x31, 0x32, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0x00 },
|
||||
{ 0x01, 0x01, 0x01, 0xB7 },
|
||||
{ 0x1E, 0x1E, 0x1E, 0xB7 },
|
||||
{ 0x03, 0x09, 0x28, 0x08 },
|
||||
{ 0x0A, 0x04, 0x2B, 0xBF },
|
||||
{ 0x17, 0x02, 0x28, 0xB7 },
|
||||
{ 0x22, 0x00, 0x1D, 0x08 },
|
||||
{ 0x24, 0x01, 0x0A, 0xB7 },
|
||||
{ 0x24, 0x04, 0x02, 0x08 },
|
||||
{ 0x1B, 0x09, 0x01, 0xB7 },
|
||||
{ 0x11, 0x10, 0x01, 0x00 },
|
||||
{ 0x05, 0x15, 0x01, 0xBF },
|
||||
{ 0x01, 0x17, 0x02, 0xB7 },
|
||||
{ 0x00, 0x14, 0x0B, 0xB7 },
|
||||
{ 0x01, 0x11, 0x1B, 0x08 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0x08 },
|
||||
{ 0x2F, 0x30, 0x2F, 0x01 },
|
||||
{ 0x05, 0x1A, 0x37, 0x08 },
|
||||
{ 0x12, 0x10, 0x3B, 0x0D },
|
||||
{ 0x23, 0x09, 0x38, 0x00 },
|
||||
{ 0x31, 0x06, 0x2E, 0xB7 },
|
||||
{ 0x35, 0x08, 0x18, 0xB7 },
|
||||
{ 0x35, 0x0D, 0x08, 0xB7 },
|
||||
{ 0x2D, 0x16, 0x03, 0xB7 },
|
||||
{ 0x22, 0x1E, 0x01, 0x00 },
|
||||
{ 0x0E, 0x24, 0x01, 0x00 },
|
||||
{ 0x05, 0x26, 0x06, 0xB7 },
|
||||
{ 0x02, 0x26, 0x16, 0x00 },
|
||||
{ 0x02, 0x22, 0x2A, 0xB7 },
|
||||
{ 0x0B, 0x0B, 0x0B, 0xB7 },
|
||||
{ 0x00, 0x00, 0x00, 0x08 },
|
||||
{ 0x00, 0x00, 0x00, 0xB7 },
|
||||
{ 0x3D, 0x3D, 0x3E, 0xB7 },
|
||||
{ 0x12, 0x2C, 0x3E, 0xBF },
|
||||
{ 0x22, 0x25, 0x3F, 0xBF },
|
||||
{ 0x30, 0x1E, 0x3E, 0xB7 },
|
||||
{ 0x3A, 0x1B, 0x3B, 0xBF },
|
||||
{ 0x3D, 0x1D, 0x2E, 0xB7 },
|
||||
{ 0x3D, 0x20, 0x1B, 0x00 },
|
||||
{ 0x3B, 0x28, 0x11, 0xB7 },
|
||||
{ 0x35, 0x30, 0x08, 0x00 },
|
||||
{ 0x26, 0x35, 0x08, 0x00 },
|
||||
{ 0x14, 0x37, 0x11, 0x00 },
|
||||
{ 0x0F, 0x37, 0x25, 0xB7 },
|
||||
{ 0x0A, 0x36, 0x37, 0xB7 },
|
||||
{ 0x18, 0x19, 0x19, 0x00 },
|
||||
{ 0x01, 0x01, 0x01, 0x00 },
|
||||
{ 0x01, 0x01, 0x01, 0x00 },
|
||||
{ 0x3E, 0x3E, 0x3E, 0x00 },
|
||||
{ 0x2D, 0x37, 0x3E, 0xB7 },
|
||||
{ 0x33, 0x34, 0x3F, 0x00 },
|
||||
{ 0x37, 0x31, 0x3E, 0xB7 },
|
||||
{ 0x3C, 0x30, 0x3D, 0xBF },
|
||||
{ 0x3D, 0x30, 0x38, 0xB7 },
|
||||
{ 0x3D, 0x33, 0x30, 0x08 },
|
||||
{ 0x3D, 0x36, 0x2B, 0x01 },
|
||||
{ 0x3B, 0x39, 0x26, 0x01 },
|
||||
{ 0x34, 0x3B, 0x27, 0x00 },
|
||||
{ 0x2E, 0x3C, 0x2D, 0xB7 },
|
||||
{ 0x2C, 0x3C, 0x36, 0xB7 },
|
||||
{ 0x29, 0x3C, 0x3C, 0x08 },
|
||||
{ 0x32, 0x31, 0x32, 0xB7 },
|
||||
{ 0x01, 0x01, 0x01, 0x08 },
|
||||
{ 0x01, 0x01, 0x01, 0xBF }
|
||||
};
|
||||
46
src/include/plugins/manager.h
Normal file
46
src/include/plugins/manager.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Plugins manager - The TI-NESulator Project
|
||||
* plugins.h
|
||||
*
|
||||
* Created by Manoel TRAPIER on 02/04/07.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate$
|
||||
* $Author$
|
||||
* $HeadURL$
|
||||
* $Revision$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PLUGINS_H
|
||||
#define PLUGINS_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/* Function pointer for prototyping function that plugins may export */
|
||||
typedef int (*PluginInit) (void);
|
||||
typedef int (*PluginDeinit) (void);
|
||||
typedef void (*PluginKeypress) (void);
|
||||
|
||||
#ifdef __TINES_PLUGINS__
|
||||
|
||||
/* Available functions for plugins */
|
||||
int plugin_install_keypressHandler(byte key, PluginKeypress);
|
||||
int plugin_remove_keypressHandler(byte key, PluginKeypress);
|
||||
|
||||
#else /* __TINES_PLUGINS__ */
|
||||
|
||||
/* Available functions outside of plugins */
|
||||
int plugin_keypress(byte key);
|
||||
|
||||
/* Real Prototype: TBD */
|
||||
void plugin_list();
|
||||
|
||||
int plugin_load(int id);
|
||||
|
||||
int plugin_unload(int id);
|
||||
|
||||
|
||||
#endif /* __TINES_PLUGINS__ */
|
||||
|
||||
#endif /* PLUGINS_H */
|
||||
24
src/include/ppu/ppu.debug.h
Normal file
24
src/include/ppu/ppu.debug.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* PPU debug utilities - The TI-NESulator Project
|
||||
* ppu.debug.h
|
||||
*
|
||||
* Created by Manoël Trapier on 12/04/07.
|
||||
* Copyright 2003-2007 986 Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-24 15:11:55 +0200 (jeu, 24 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/ppu/ppu.debug.h $
|
||||
* $Revision: 53 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __TINES_PPU_INTERNAL__
|
||||
|
||||
void ppu_dumpPalette(int x, int y);
|
||||
void ppu_dumpPattern(int xd, int yd);
|
||||
void ppu_dumpNameTable(int xd, int yd);
|
||||
void ppu_dumpAttributeTable(int xd, int yd);
|
||||
|
||||
#else
|
||||
#error Must only be included inside the PPU code
|
||||
#endif
|
||||
68
src/include/ppu/ppu.h
Executable file
68
src/include/ppu/ppu.h
Executable file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* PPU emulation - The TI-NESulator Project
|
||||
* ppu.h
|
||||
*
|
||||
* Define and emulate the PPU (Picture Processing Unit) of the real NES
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-26 18:47:34 +0200 (jeu, 26 avr 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/ppu.h $
|
||||
* $Revision: 46 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PPU_H
|
||||
#define PPU_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef struct PPU_Sprite_
|
||||
{
|
||||
byte y;
|
||||
byte tileid;
|
||||
byte flags;
|
||||
byte x;
|
||||
} PPU_Sprite;
|
||||
|
||||
/*
|
||||
PPU must be initialized after memory initialisation..
|
||||
*/
|
||||
int ppu_init();
|
||||
|
||||
int ppu_hblank(int scanline);
|
||||
|
||||
byte ppu_readReg(byte id);
|
||||
|
||||
void ppu_writeReg(byte id, byte val);
|
||||
|
||||
void ppu_fillSprRamDMA(byte value);
|
||||
|
||||
#define PPU_MIRROR_HORIZTAL 0
|
||||
#define PPU_MIRROR_VERTICAL 1
|
||||
|
||||
#define PPU_SCREEN_000 0
|
||||
#define PPU_SCREEN_400 1
|
||||
#define PPU_SCREEN_800 2
|
||||
#define PPU_SCREEN_C00 3
|
||||
|
||||
#define PPU_SCMODE_SINGLE 0
|
||||
#define PPU_SCMODE_NORMAL 1
|
||||
#define PPU_SCMODE_FOURSC 2
|
||||
|
||||
void ppu_setMirroring(byte direction);
|
||||
void ppu_setSingleScreen(byte screen);
|
||||
void ppu_setScreenMode(byte mode);
|
||||
|
||||
|
||||
PPU_Sprite ppu_getSprite(unsigned short i);
|
||||
|
||||
unsigned char ppu_memoryRead(byte page, byte addr);
|
||||
void ppu_memoryWrite(byte page, byte addr, byte value);
|
||||
|
||||
void ppu_debugSprites();
|
||||
void ppu_debugColor();
|
||||
|
||||
#endif
|
||||
32
src/include/ppu/ppu.memory.h
Normal file
32
src/include/ppu/ppu.memory.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* PPU Memory manager - The TI-NESulator Project
|
||||
* ppu.memory.h - Inspired from the memory manager of the Quick6502 Project.
|
||||
*
|
||||
* Created by Manoël Trapier on 12/04/07.
|
||||
* Copyright 2003-2007 986 Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-24 15:11:55 +0200 (jeu, 24 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/ppu/ppu.memory.h $
|
||||
* $Revision: 53 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __TINES_PPU_INTERNAL__
|
||||
|
||||
int ppu_initMemory();
|
||||
|
||||
void ppu_setPagePtr (byte page, byte *ptr);
|
||||
void ppu_setPagePtr1k(byte page, byte *ptr);
|
||||
void ppu_setPagePtr2k(byte page, byte *ptr);
|
||||
void ppu_setPagePtr4k(byte page, byte *ptr);
|
||||
void ppu_setPagePtr8k(byte page, byte *ptr);
|
||||
|
||||
void ppu_memoryDumpState(FILE *fp);
|
||||
|
||||
byte ppu_readMemory(byte page, byte addr);
|
||||
void ppu_writeMemory(byte page, byte addr, byte value);
|
||||
|
||||
#else
|
||||
#error Must only be included inside the PPU code
|
||||
#endif
|
||||
28
src/include/types.h
Executable file
28
src/include/types.h
Executable file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Base type definitions - The TI-NESulator Project
|
||||
* types.h - Taken from the Quick6502 project
|
||||
*
|
||||
* Created by Manoël Trapier on 18/09/06.
|
||||
* Copyright 2003-2007 986 Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-03-28 15:50:50 +0200 (mer, 28 mar 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/types.h $
|
||||
* $Revision: 25 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#ifndef BYTE_TYPE_DEFINED
|
||||
#define BYTE_TYPE_DEFINED
|
||||
typedef unsigned char byte;
|
||||
#endif
|
||||
|
||||
typedef unsigned char bool;
|
||||
|
||||
#define true (0)
|
||||
#define false (!true)
|
||||
|
||||
#endif
|
||||
1232
src/main.c
Executable file
1232
src/main.c
Executable file
File diff suppressed because it is too large
Load Diff
62
src/mappersmanager/manager.c
Normal file
62
src/mappersmanager/manager.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* manager.c
|
||||
* TI-NESulator.X
|
||||
*
|
||||
* Created by Manoël Trapier on 07/10/07.
|
||||
* Copyright 2007 986 Corp. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <mappers/manager.h>
|
||||
|
||||
MapperIRQ mapper_irqloop;
|
||||
MapperDump mapper_dump;
|
||||
MapperWriteHook mapper_hook;
|
||||
|
||||
typedef struct Mapper_
|
||||
{
|
||||
byte id;
|
||||
byte *name;
|
||||
|
||||
MapperInit init;
|
||||
MapperIRQ irq;
|
||||
MapperDump dump;
|
||||
|
||||
} Mapper;
|
||||
|
||||
#include "mappers_list.h"
|
||||
|
||||
void mapper_list ()
|
||||
{
|
||||
Mapper *ptr = &(Mappers[0]);
|
||||
printf("Available mapers:\n");
|
||||
while(ptr->name != NULL)
|
||||
{
|
||||
printf("%d - %s\n", ptr->id, ptr->name);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
int mapper_init (NesCart *cart)
|
||||
{
|
||||
Mapper *ptr = &(Mappers[0]);
|
||||
printf ("Search for a compatible mapper ID #%X:\n", cart->MapperID);
|
||||
while (ptr->name != NULL)
|
||||
{
|
||||
if (ptr->id == cart->MapperID)
|
||||
{
|
||||
printf ("Found mapper ID #%X - '%s'\n", ptr->id, ptr->name);
|
||||
ptr->init (cart);
|
||||
|
||||
mapper_irqloop = ptr->irq;
|
||||
mapper_dump = ptr->dump;
|
||||
|
||||
return 0;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
361
src/mappersmanager/mappers/mmc1.c
Executable file
361
src/mappersmanager/mappers/mmc1.c
Executable file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* MMC1 Mapper - The TI-NESulator Project
|
||||
* mmc1.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-02 18:37:41 +0200 (mer, 02 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/mmc1.h $
|
||||
* $Revision: 50 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "norom.h"
|
||||
|
||||
#include <ppu/ppu.h>
|
||||
#include <memory/manager.h>
|
||||
|
||||
unsigned char MMC1_reg0;
|
||||
|
||||
unsigned char MMC1_reg1;
|
||||
|
||||
unsigned char MMC1_reg2;
|
||||
|
||||
unsigned char MMC1_reg3;
|
||||
|
||||
unsigned char mmc1_CurrentBank;
|
||||
|
||||
#define MMC1_R0_MIRROR 0x01
|
||||
#define MMC1_R0_ONESCREEN 0x02
|
||||
#define MMC1_R0_PRGAREA 0x04
|
||||
#define MMC1_R0_PRGSIZE 0x08
|
||||
#define MMC1_R0_VROMSW 0x10
|
||||
#define MMC1_R0_RESET 0x80
|
||||
|
||||
#define MMC1_R1_VROMB1 0x0F
|
||||
#define MMC1_R1_256KSEL 0x10
|
||||
#define MMC1_R1_RESET 0x80
|
||||
|
||||
#define MMC1_R2_VROMB2 0x0F
|
||||
#define MMC1_R2_256KSEL 0x10
|
||||
#define MMC1_R2_RESET 0x80
|
||||
|
||||
#define MMC1_R3_VROMB2 0x0F
|
||||
#define MMC1_R3_SAVECE 0x10
|
||||
#define MMC1_R3_RESET 0x80
|
||||
|
||||
|
||||
#define MMC1_REG0_DEFAULT MMC1_R0_PRGSIZE | MMC1_R0_PRGAREA
|
||||
#define MMC1_REG1_DEFAULT 0
|
||||
#define MMC1_REG2_DEFAULT 0
|
||||
#define MMC1_REG3_DEFAULT 0
|
||||
|
||||
|
||||
void mmc1_MapperWriteReg0(register byte Addr, register byte Value);
|
||||
void mmc1_MapperWriteReg1(register byte Addr, register byte Value);
|
||||
void mmc1_MapperWriteReg2(register byte Addr, register byte Value);
|
||||
void mmc1_MapperWriteReg3(register byte Addr, register byte Value);
|
||||
|
||||
void mmc1_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"MMC1: r0:0x%02X r1:0x%02X r2:0x%02X r3:0x%02X\n",MMC1_reg0,MMC1_reg1,MMC1_reg2,MMC1_reg3);
|
||||
}
|
||||
|
||||
int mmc1_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
MMC1_reg0 = MMC1_REG0_DEFAULT;
|
||||
|
||||
MMC1_reg1 = MMC1_REG1_DEFAULT;
|
||||
|
||||
MMC1_reg2 = MMC1_REG2_DEFAULT;
|
||||
|
||||
MMC1_reg3 = MMC1_REG3_DEFAULT;
|
||||
|
||||
set_prom_bank_16k(0x8000,0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
mmc1_CurrentBank = 0;
|
||||
|
||||
if (cart->VROMSize > 0)
|
||||
set_vrom_bank_4k(0x0000,0);
|
||||
|
||||
|
||||
/* Mapper should register itself for write hook */
|
||||
for (i = 0x80; i < 0xA0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg0);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xA0; i < 0xC0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg1);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xC0; i < 0xE0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg2);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xE0; i < 0x100 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg3);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Reg 0
|
||||
8 : 1000
|
||||
9 : 1001
|
||||
|
||||
Reg 1
|
||||
A : 1010
|
||||
B : 1011
|
||||
|
||||
Reg 2
|
||||
C : 1100
|
||||
D : 1101
|
||||
|
||||
Reg 3
|
||||
E : 1110
|
||||
F : 1111
|
||||
|
||||
((Addr & 0x6000) >> 13) <- port number
|
||||
*/
|
||||
#define MMC1_GetReg(a) ((a & 0x6000) >> 13)
|
||||
/* (Val & 0x01) recuperation du bit */
|
||||
#define MMC1_GetBit(v) (v & 0x01)
|
||||
/* ( ( b & (1 << Bit)) | (v << Bit) ) Ajout du bit */
|
||||
#define MMC1_AddBit(b,v) ( ( b & ~(1 << Bit)) | (v << Bit) )
|
||||
|
||||
void mmc1_ApplyReg0Mod()
|
||||
{
|
||||
|
||||
static unsigned char OldSwitchArea = MMC1_R0_PRGAREA;
|
||||
|
||||
|
||||
|
||||
//printf("Change to reg0 done ! (0x%x)\n\tMiror flag : %d\n\tOneScreen Flag : %d\n\tPRG Size : %d\n\tPRG Area : %d\n\tVROM Switch size : %d\n", MMC1_reg0, MMC1_reg0 & MMC1_R0_MIRROR, MMC1_reg0 & MMC1_R0_ONESCREEN, MMC1_reg0 & MMC1_R0_PRGAREA, MMC1_reg0 & MMC1_R0_PRGSIZE, MMC1_reg0 & MMC1_R0_VROMSW);
|
||||
|
||||
switch (MMC1_reg0 & 0x03)
|
||||
{
|
||||
case 0:
|
||||
ppu_setScreenMode(PPU_SCMODE_SINGLE);
|
||||
ppu_setSingleScreen(PPU_SCREEN_000);
|
||||
break;
|
||||
case 1:
|
||||
ppu_setScreenMode(PPU_SCMODE_SINGLE);
|
||||
ppu_setSingleScreen(PPU_SCREEN_400);
|
||||
break;
|
||||
case 2:
|
||||
ppu_setScreenMode(PPU_SCMODE_NORMAL);
|
||||
ppu_setMirroring(PPU_MIRROR_VERTICAL);
|
||||
break;
|
||||
case 3:
|
||||
ppu_setScreenMode(PPU_SCMODE_NORMAL);
|
||||
ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (OldSwitchArea != (MMC1_reg0 & MMC1_R0_PRGAREA)) && ((MMC1_reg0 & MMC1_R0_PRGSIZE) != 0 ) )
|
||||
{
|
||||
|
||||
if ((MMC1_reg0 & MMC1_R0_PRGAREA) != 0)
|
||||
{ /* 0x8000 area */
|
||||
set_prom_bank_16k(0x8000,mmc1_CurrentBank);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(Cart));
|
||||
}
|
||||
else
|
||||
{ /* 0xC000 area */
|
||||
|
||||
set_prom_bank_16k(0x8000,0);
|
||||
set_prom_bank_16k(0xC000,mmc1_CurrentBank);
|
||||
|
||||
}
|
||||
|
||||
OldSwitchArea = (MMC1_reg0 & MMC1_R0_PRGAREA);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int VROMBankNb;
|
||||
unsigned char Bit = 0;
|
||||
unsigned char BitBuf = 0;
|
||||
|
||||
void mmc1_MapperWriteReg0(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg0 = MMC1_REG0_DEFAULT;
|
||||
printf("MMC1: Reg0 Reset occured !\n");
|
||||
mmc1_ApplyReg0Mod();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg0 = BitBuf;
|
||||
|
||||
mmc1_ApplyReg0Mod();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mmc1_MapperWriteReg1(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg1 = MMC1_REG1_DEFAULT;
|
||||
printf("MMC1: Reg1 Reset occured !\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg1 = BitBuf;
|
||||
|
||||
VROMBankNb = (MMC1_reg1 /* & MMC1_R1_VROMB1 */ );
|
||||
|
||||
if (Cart->VROMSize == 0)
|
||||
{
|
||||
printf("Try to change VROM but with didn't have any VROM ! [%04X]\n", VROMBankNb);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (MMC1_reg0 & MMC1_R0_VROMSW) != 0 )
|
||||
{ /* 4K vram */
|
||||
//printf("Switching VROM at 0x0000 to 4k bank %d\n", VROMBankNb);
|
||||
set_vrom_bank_4k(0x0000,VROMBankNb);
|
||||
}
|
||||
else
|
||||
{ /* 8K vram */
|
||||
//printf("Switching VROM at 0x0000 to 8k bank %d\n", VROMBankNb>>1);
|
||||
set_vrom_bank_8k(0x0000,VROMBankNb>>1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mmc1_MapperWriteReg2(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg2 = MMC1_REG2_DEFAULT;
|
||||
printf("MMC1: Reg2 Reset occured !\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg2 = BitBuf;
|
||||
|
||||
VROMBankNb = (MMC1_reg2 /* & MMC1_R2_VROMB2 */ );
|
||||
|
||||
//printf("Want to switch VROM at 0x1000 to 4k bank %d\n", VROMBankNb);
|
||||
if (Cart->VROMSize == 0)
|
||||
{
|
||||
//printf(": No\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (MMC1_reg0 & MMC1_R0_VROMSW) != 0 )
|
||||
{ /* 4K vram */
|
||||
//printf("Switching VROM at 0x1000 to 4k bank %d\n", VROMBankNb);
|
||||
set_vrom_bank_4k(0x1000,VROMBankNb);
|
||||
}
|
||||
else
|
||||
{ /* 8K vram */
|
||||
// printf("Switching VROM at 0x1000 to 8k bank %d\n", VROMBankNb>>1);
|
||||
// set_vrom_bank_8k(0x1000,VROMBankNb>>1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mmc1_MapperWriteReg3(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg3 = MMC1_REG3_DEFAULT;
|
||||
printf("MMC1: Reg3 Reset occured !\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg3 = BitBuf;
|
||||
|
||||
if (MMC1_reg3<<14 > Cart->PROMSize)
|
||||
return;
|
||||
|
||||
if ( (MMC1_reg0 & MMC1_R0_PRGSIZE) != 0 )
|
||||
{ /* 16K Switch */
|
||||
if ( (MMC1_reg0 & MMC1_R0_PRGAREA) != 0 )
|
||||
{ /* 0x8000 switch */
|
||||
set_prom_bank_16k(0x8000,MMC1_reg3);
|
||||
//printf("LowBank is now %d ( 0x%p )\n", MMC1_reg3, mLBank);
|
||||
}
|
||||
else
|
||||
{ /* 0xC000 switch */
|
||||
set_prom_bank_16k(0xC000,MMC1_reg3);
|
||||
//printf("HighBank is now %d ( 0x%p )\n", MMC1_reg3, mUBank);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* 32K Switch */
|
||||
set_prom_bank_32k(0x8000,MMC1_reg3>>1);
|
||||
}
|
||||
|
||||
if ( ( MMC1_reg3 & MMC1_R3_SAVECE ) != 0)
|
||||
{
|
||||
unmap_sram();
|
||||
}
|
||||
else
|
||||
{
|
||||
map_sram();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("MMC1: Debug (Reg:%d,Val:0x%02X,reg0:0x%02X,reg1:0x%02X,reg2:0x%02X,reg3:0x%02X)\n", MMC1_GetReg(Addr), Value, MMC1_reg0, MMC1_reg1, MMC1_reg2, MMC1_reg3);
|
||||
16
src/mappersmanager/mappers/mmc1.h
Normal file
16
src/mappersmanager/mappers/mmc1.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* mmc1.h
|
||||
* TI-NESulator.X
|
||||
*
|
||||
* Created by Manoël Trapier on 02/12/07.
|
||||
* Copyright 2007 986 Corp. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define __TINES_MAPPERS__
|
||||
#include <mappers/manager.h>
|
||||
|
||||
int mmc1_InitMapper (NesCart *cart);
|
||||
int mmc1_MapperIRQ (int cycledone);
|
||||
void mmc1_MapperDump ();
|
||||
void mmc1_MapperWriteHook(register byte Addr, register byte Value);
|
||||
48
src/mappersmanager/mappers/norom.c
Normal file
48
src/mappersmanager/mappers/norom.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* norom.c
|
||||
* TI-NESulator.X
|
||||
*
|
||||
* Created by Manoël Trapier on 25/10/07.
|
||||
* Copyright 2007 986 Corp. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "norom.h"
|
||||
|
||||
int norom_InitMapper(NesCart *cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_page_ptr_16k(0x80, cart->PROMBanks);
|
||||
|
||||
/* mUBank = 0xC000 */
|
||||
if (cart->PROMSize > (16*1024))
|
||||
{
|
||||
set_prom_bank_16k(0xC000, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_prom_bank_16k(0xC000, 0);
|
||||
}
|
||||
|
||||
if (cart->VROMSize > 0)
|
||||
set_vrom_bank_8k(0x2000, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int norom_MapperIRQ(int cycledone)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void norom_MapperWriteHook(register byte Addr, register byte Value)
|
||||
{
|
||||
/* Nothing to do */
|
||||
return;
|
||||
}
|
||||
|
||||
void norom_MapperDump (FILE *fp)
|
||||
{
|
||||
fprintf(fp, "norom mapper have nothing to dump");
|
||||
}
|
||||
16
src/mappersmanager/mappers/norom.h
Normal file
16
src/mappersmanager/mappers/norom.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* norom.h
|
||||
* TI-NESulator.X
|
||||
*
|
||||
* Created by Manoël Trapier on 25/10/07.
|
||||
* Copyright 2007 986 Corp. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define __TINES_MAPPERS__
|
||||
#include <mappers/manager.h>
|
||||
|
||||
int norom_InitMapper (NesCart *cart);
|
||||
int norom_MapperIRQ (int cycledone);
|
||||
void norom_MapperDump ();
|
||||
void norom_MapperWriteHook(register byte Addr, register byte Value);
|
||||
63
src/mappersmanager/mappers/temp/aorom.c
Executable file
63
src/mappersmanager/mappers/temp/aorom.c
Executable file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* AOROM Mapper - The TI-NESulator Project
|
||||
* aorom.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-26 18:47:34 +0200 (jeu, 26 avr 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/aorom.h $
|
||||
* $Revision: 46 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned char aorom_load_bank;
|
||||
|
||||
void aorom_MapperWriteHook(register byte Addr, register byte Value);
|
||||
|
||||
extern byte *ppu_mem_nameTables;
|
||||
|
||||
int aorom_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_32k(0x8000,0);
|
||||
|
||||
ppu_setScreenMode(PPU_SCMODE_SINGLE);
|
||||
|
||||
aorom_load_bank = 0;
|
||||
|
||||
/* Register the write hook */
|
||||
for (i = 0x80; i < 0x100; i++)
|
||||
{
|
||||
set_page_wr_hook(i, aorom_MapperWriteHook);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void aorom_MapperWriteHook(register byte Addr, register byte Value)
|
||||
{
|
||||
int BankNb;
|
||||
|
||||
if (Value & (1 << 4))
|
||||
ppu_setSingleScreen(PPU_SCREEN_000);
|
||||
else
|
||||
ppu_setSingleScreen(PPU_SCREEN_400);
|
||||
|
||||
BankNb = Value & 0x0F;
|
||||
|
||||
aorom_load_bank = BankNb;
|
||||
|
||||
//printf("aorom: Asking bank %d (giving %d & %d) - mirror is %d\n",BankNb,BankNb,(Value<<1)+1,Value&0x0F);
|
||||
set_prom_bank_32k(0x8000,BankNb);
|
||||
}
|
||||
|
||||
void aorom_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"aorom: bank:%d\n",aorom_load_bank);
|
||||
}
|
||||
47
src/mappersmanager/mappers/temp/cnrom.c
Executable file
47
src/mappersmanager/mappers/temp/cnrom.c
Executable file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* CNROM Mapper - The TI-NESulator Project
|
||||
* cnrom.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/cnrom.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned char cnrom_load_bank;
|
||||
|
||||
void cnrom_MapperWriteHook(register byte Addr, register byte Value);
|
||||
|
||||
int cnrom_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0x8000, 0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart)); /* Set the last one */
|
||||
cnrom_load_bank = 0;
|
||||
|
||||
/* Register the write hook */
|
||||
for (i = 0x80; i < 0x100; i++)
|
||||
{
|
||||
set_page_wr_hook(i, cnrom_MapperWriteHook);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void cnrom_MapperWriteHook(register byte Addr, register byte Value)
|
||||
{
|
||||
set_prom_bank_16k(0x8000,Value);
|
||||
cnrom_load_bank = Value;
|
||||
}
|
||||
|
||||
void cnrom_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"cnrom: bank:%d\n",cnrom_load_bank);
|
||||
}
|
||||
35
src/mappersmanager/mappers/temp/genericmapper.c
Executable file
35
src/mappersmanager/mappers/temp/genericmapper.c
Executable file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Generic mapper implementation - The TI-NESulator Project
|
||||
* genericmapper.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/genericmapper.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
int _InitMapper(NesCart * cart)
|
||||
{
|
||||
|
||||
set_prom_bank_16k(0xC000,0);
|
||||
set_prom_bank_16k(0x8000,-1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int _MapperWriteHook(register word Addr, register byte Value)
|
||||
{
|
||||
|
||||
if (Addr > 0x7FFF) /* Try to write to the rom */
|
||||
{
|
||||
set_vrom_bank_8k(0x0000,Value)
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
125
src/mappersmanager/mappers/temp/iremh3001.c
Executable file
125
src/mappersmanager/mappers/temp/iremh3001.c
Executable file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* IREMH3001 Mapper - The TI-NESulator Project
|
||||
* iremh3001.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/iremh3001.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned short iremh3001_prom_slot[3];
|
||||
|
||||
unsigned short iremh3001_vrom_slot[8];
|
||||
|
||||
int iremh3001_InitMapper(NesCart * cart)
|
||||
{
|
||||
|
||||
set_prom_bank_16k(0x8000, 0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
iremh3001_prom_slot[0] = 0;
|
||||
iremh3001_prom_slot[1] = 1;
|
||||
iremh3001_prom_slot[2] = GETLAST16KBANK(cart);
|
||||
|
||||
set_vrom_bank_8k(0x0000,4);
|
||||
|
||||
iremh3001_vrom_slot[0] = 0;
|
||||
iremh3001_vrom_slot[1] = 0;
|
||||
iremh3001_vrom_slot[2] = 0;
|
||||
iremh3001_vrom_slot[3] = 0;
|
||||
iremh3001_vrom_slot[4] = 0;
|
||||
iremh3001_vrom_slot[5] = 0;
|
||||
iremh3001_vrom_slot[6] = 0;
|
||||
iremh3001_vrom_slot[7] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int iremh3001_MapperWriteHook(register word Addr, register byte Value)
|
||||
{
|
||||
|
||||
switch(Addr)
|
||||
{
|
||||
case 0x8000: /* Set 8k PROM @ 8000 */
|
||||
printf("iremh3001: %X: change PROM to %d[%X]\n", Addr, Value, Value);
|
||||
set_prom_bank_8k(0x8000, Value);
|
||||
iremh3001_prom_slot[0] = Value;
|
||||
break;
|
||||
|
||||
case 0x9003: /* Mirroring ??? */
|
||||
printf("iremh3001: Mirroring[0x%X:%d] ?\n", Value, Value);
|
||||
break;
|
||||
|
||||
case 0x9005: /* IRQ ??? */
|
||||
printf("iremh3001: IRQ[0x%X:%d] ?\n", Value, Value);
|
||||
break;
|
||||
|
||||
case 0x9006: /* IRQ ??? */
|
||||
printf("iremh3001: IRQ[0x%X:%d] ?\n", Value, Value);
|
||||
break;
|
||||
|
||||
case 0xA000: /* Set 8k PROM @ A000 */
|
||||
printf("iremh3001: %X: change PROM to %d[%X]\n", Addr, Value, Value);
|
||||
set_prom_bank_8k(0xA000, Value);
|
||||
iremh3001_prom_slot[1] = Value;
|
||||
break;
|
||||
|
||||
case 0xB000: /* Set 1k VROM @ 0000 */
|
||||
case 0xB001: /* Set 1k VROM @ 0400 */
|
||||
case 0xB002: /* Set 1k VROM @ 0800 */
|
||||
case 0xB003: /* Set 1k VROM @ 0C00 */
|
||||
case 0xB004: /* Set 1k VROM @ 1000 */
|
||||
case 0xB005: /* Set 1k VROM @ 1400 */
|
||||
case 0xB006: /* Set 1k VROM @ 1800 */
|
||||
case 0xB007: /* Set 1k VROM @ 1C00 */
|
||||
printf("iremh3001: %X: change VROM to %d[%X]\n", (Addr&0x0F)<<10, Value, Value);
|
||||
set_vrom_bank_1k((Addr&0xF)<<10, Value);
|
||||
iremh3001_vrom_slot[Addr&0x0F] = Value;
|
||||
break;
|
||||
|
||||
case 0xC000: /* Set 8k PROM @ C000 */
|
||||
printf("iremh3001: %X: change PROM to %d[%X]\n", Addr, Value, Value);
|
||||
set_prom_bank_8k(0xC000, Value);
|
||||
iremh3001_prom_slot[2] = Value;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("@:%X -- V:%X", Addr, Value);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void iremh3001_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"iremh3001: prom: $8000:%d $A000:%d $C000:%d\n",
|
||||
iremh3001_prom_slot[0],
|
||||
iremh3001_prom_slot[1],
|
||||
iremh3001_prom_slot[2]);
|
||||
|
||||
fprintf(fp,"iremh3001: vrom: $0000:%d $0400:%d $0800:%d $0C00:%d\n" \
|
||||
" $1000:%d $1400:%d $1800:%d $1C00:%d\n",
|
||||
iremh3001_vrom_slot[0],
|
||||
iremh3001_vrom_slot[1],
|
||||
iremh3001_vrom_slot[2],
|
||||
iremh3001_vrom_slot[3],
|
||||
iremh3001_vrom_slot[4],
|
||||
iremh3001_vrom_slot[5],
|
||||
iremh3001_vrom_slot[6],
|
||||
iremh3001_prom_slot[7]);
|
||||
}
|
||||
|
||||
|
||||
int iremh3001_MapperIRQ(int cycledone)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
317
src/mappersmanager/mappers/temp/mmc3.c
Executable file
317
src/mappersmanager/mappers/temp/mmc3.c
Executable file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* MMC3 Mapper - The TI-NESulator Project
|
||||
* mmc3.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-02 18:37:41 +0200 (mer, 02 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/mmc3.h $
|
||||
* $Revision: 50 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned short mmc3_command;
|
||||
|
||||
unsigned char mmc3_irq_counter;
|
||||
unsigned char mmc3_irq_counter_reload;
|
||||
unsigned char mmc3_irq_enable;
|
||||
|
||||
unsigned short mmc3_first_prom_page;
|
||||
unsigned short mmc3_second_prom_page;
|
||||
|
||||
unsigned char mmc3_use_xor;
|
||||
unsigned char mmc3_last_vrom[6];
|
||||
|
||||
unsigned char mmc3_last_prom[2];
|
||||
unsigned char mmc3_last_prom_switch;
|
||||
|
||||
unsigned short dummy;
|
||||
|
||||
void mmc3_MapperWrite80Hook(byte addr, byte value);
|
||||
void mmc3_MapperWriteA0Hook(byte addr, byte value);
|
||||
void mmc3_MapperWriteC0Hook(byte addr, byte value);
|
||||
void mmc3_MapperWriteE0Hook(byte addr, byte value);
|
||||
|
||||
void mmc3_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"MMC3: CMD:%d IC:%d IR:%d IE:%d FPP:0x%04X SPP:0x%04X UX:%d\n",mmc3_command,mmc3_irq_counter,mmc3_irq_counter_reload,mmc3_irq_enable,mmc3_first_prom_page,mmc3_second_prom_page,mmc3_use_xor);
|
||||
fprintf(fp,"MMC3: LV0:%d LV1:%d LV2:%d LV3:%d LV4:%d LV5:%d\n",mmc3_last_vrom[0],mmc3_last_vrom[1],mmc3_last_vrom[2],mmc3_last_vrom[3],mmc3_last_vrom[4],mmc3_last_vrom[5]);
|
||||
fprintf(fp,"MMC3: LP0:%d LP1:%d LPS:%d\n",mmc3_last_prom[0],mmc3_last_prom[1],mmc3_last_prom_switch);
|
||||
}
|
||||
|
||||
int mmc3_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0x8000, 0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
if ( Cart->VROMSize > 0)
|
||||
{
|
||||
set_vrom_bank_8k(0, 0x0000);
|
||||
}
|
||||
|
||||
mmc3_command = -1;
|
||||
|
||||
mmc3_irq_counter = -1;
|
||||
mmc3_irq_enable = 1;
|
||||
mmc3_irq_counter_reload = 0;
|
||||
|
||||
mmc3_use_xor = 0x42;
|
||||
|
||||
mmc3_last_prom_switch = 0x42;
|
||||
|
||||
mmc3_last_prom[0] = 0;
|
||||
mmc3_last_prom[1] = 1;
|
||||
|
||||
mmc3_last_vrom[0] = 0;
|
||||
mmc3_last_vrom[1] = 2;
|
||||
mmc3_last_vrom[2] = 3;
|
||||
mmc3_last_vrom[3] = 4;
|
||||
mmc3_last_vrom[4] = 5;
|
||||
mmc3_last_vrom[5] = 6;
|
||||
|
||||
mmc3_first_prom_page = 0x8000;
|
||||
mmc3_second_prom_page = 0xA000;
|
||||
//mmc3_first_prom_page = 0; // Set it to 0x8000
|
||||
|
||||
|
||||
/* Register mapper write hook */
|
||||
set_page_wr_hook(0x80, mmc3_MapperWrite80Hook);
|
||||
set_page_writeable(0x80, true);
|
||||
|
||||
set_page_wr_hook(0xA0, mmc3_MapperWriteA0Hook);
|
||||
set_page_writeable(0xA0, true);
|
||||
|
||||
set_page_wr_hook(0xC0, mmc3_MapperWriteC0Hook);
|
||||
set_page_writeable(0xC0, true);
|
||||
|
||||
set_page_wr_hook(0xE0, mmc3_MapperWriteE0Hook);
|
||||
set_page_writeable(0xE0, true);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void mmc3_MapperWrite80Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
|
||||
if ((Cart->VROMSize > 0) && ( mmc3_use_xor != (Value & 0x80) ))
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
set_vrom_bank_1k(0x0000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x0400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x0800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x0C00, mmc3_last_vrom[5]);
|
||||
set_vrom_bank_2k(0x1000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x1800, mmc3_last_vrom[1]>>1);
|
||||
//chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1
|
||||
}
|
||||
else
|
||||
{
|
||||
set_vrom_bank_2k(0x0000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x0800, mmc3_last_vrom[1]>>1);
|
||||
set_vrom_bank_1k(0x1000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x1400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x1800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x1C00, mmc3_last_vrom[5]);
|
||||
//chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7
|
||||
}
|
||||
mmc3_use_xor = (Value & 0x80);
|
||||
}
|
||||
|
||||
|
||||
if (mmc3_last_prom_switch != (Value & 0x40))
|
||||
{
|
||||
if (!(Value & 0x40))
|
||||
{
|
||||
printf("MMC3: Switch -> 8/A\n");
|
||||
mmc3_first_prom_page = 0x8000;
|
||||
mmc3_second_prom_page = 0xA000;
|
||||
|
||||
set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
|
||||
set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
|
||||
|
||||
set_prom_bank_8k(0xC000, GETLAST08KBANK(Cart)-1);
|
||||
//set_prom_bank_8k(0xE000, GETLAST08KBANK(cart));
|
||||
//prg_bank(prg0,prg1,max_prg-1,max_prg);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("MMC3: Switch -> C/A\n");
|
||||
mmc3_first_prom_page = 0xC000;
|
||||
mmc3_second_prom_page = 0xA000;
|
||||
|
||||
set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
|
||||
set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
|
||||
|
||||
set_prom_bank_8k(0x8000, GETLAST08KBANK(Cart)-1);
|
||||
|
||||
|
||||
//prg_bank(max_prg-1,prg1,prg0,max_prg);
|
||||
}
|
||||
mmc3_last_prom_switch = (Value & 0x40);
|
||||
}
|
||||
mmc3_command = Value & 0x07;
|
||||
|
||||
|
||||
|
||||
} else { /* 8001 */
|
||||
switch (mmc3_command)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
if (Cart->VROMSize == 0)
|
||||
return;
|
||||
|
||||
mmc3_last_vrom[mmc3_command] = Value;
|
||||
|
||||
if (mmc3_use_xor)
|
||||
{
|
||||
set_vrom_bank_1k(0x0000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x0400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x0800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x0C00, mmc3_last_vrom[5]);
|
||||
set_vrom_bank_2k(0x1000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x1800, mmc3_last_vrom[1]>>1);
|
||||
//chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1
|
||||
}
|
||||
else
|
||||
{
|
||||
set_vrom_bank_2k(0x0000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x0800, mmc3_last_vrom[1]>>1);
|
||||
set_vrom_bank_1k(0x1000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x1400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x1800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x1C00, mmc3_last_vrom[5]);
|
||||
//chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
mmc3_last_prom[0] = Value;
|
||||
set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
mmc3_last_prom[1] = Value;
|
||||
set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/*if(mmc3_use_xor)
|
||||
chr_bank(chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1);
|
||||
else
|
||||
chr_bank(chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7);*/
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void mmc3_MapperWriteA0Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
//printf("MMC3: Select mirroring (0xA000) : 0x%X\n",Value);
|
||||
|
||||
if (Value & 0x1)
|
||||
ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
else
|
||||
ppu_setMirroring(PPU_MIRROR_VERTICAL);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("MMC3: SaveRAM Toggle (0xA001) : 0x%X\n",Value);
|
||||
if (Value)
|
||||
map_sram();
|
||||
else
|
||||
unmap_sram();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern unsigned short ScanLine;
|
||||
|
||||
void mmc3_MapperWriteC0Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
mmc3_irq_counter_reload = Value;
|
||||
mmc3_irq_counter = Value;
|
||||
//printf("MMC3 IRQ[%d]: SetIRQ reload to %d\n", ScanLine, Value);
|
||||
|
||||
}else{ /* C001 */
|
||||
//printf("MMC3: New tmp IRQ value (0xC001) : 0x%X\n",Value);
|
||||
//printf("MMC3 IRQ[%d]: Reset IRQ counter to val %d [Value = %d]\n", ScanLine, mmc3_irq_counter_reload, Value);
|
||||
mmc3_irq_counter = Value;
|
||||
}
|
||||
}
|
||||
|
||||
void mmc3_MapperWriteE0Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
//printf("MMC3: Writing to 0xE001 : 0x%X\n",Value);
|
||||
//printf("MMC3 IRQ[%d]: IRQ disabled\n", ScanLine);
|
||||
mmc3_irq_enable = 0;
|
||||
//MapperWantIRQ = 1;
|
||||
// Add a way to raise an IRQ
|
||||
|
||||
}else{ /* E001 */
|
||||
//printf("MMC3: Writing to 0xE001 : 0x%X\n",Value);
|
||||
//printf("MMC3: IRQ Enabled (value : %d)\n",mmc3_irq_counter);
|
||||
//printf("MMC3 IRQ[%d]: Enable IRQ\nr", ScanLine);
|
||||
mmc3_irq_enable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int mmc3_MapperIRQ(int cycledone)
|
||||
{
|
||||
if (((cycledone > 0) && (cycledone < 241)) /*&&
|
||||
(ppu.ControlRegister2.b & (PPU_CR2_BGVISIBILITY | PPU_CR2_SPRTVISIBILITY)) == (PPU_CR2_BGVISIBILITY | PPU_CR2_SPRTVISIBILITY)*/)
|
||||
{
|
||||
|
||||
if ((mmc3_irq_counter --) > 0 )return 0;
|
||||
|
||||
|
||||
/* Load next counter position */
|
||||
mmc3_irq_counter = mmc3_irq_counter_reload;
|
||||
|
||||
if (mmc3_irq_enable == 0) return 0;
|
||||
|
||||
mmc3_irq_enable = 0;
|
||||
|
||||
//printf("MMC3 IRQ[%d]: Tick next at %d\n", ScanLine, mmc3_irq_counter_reload);
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
137
src/mappersmanager/mappers/temp/mmc4.c
Normal file
137
src/mappersmanager/mappers/temp/mmc4.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* MMC4 Mapper - The TI-NESulator Project
|
||||
* mmc4.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-31 18:00:41 +0200 (jeu, 31 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/mmc4.h $
|
||||
* $Revision: 56 $
|
||||
*
|
||||
*/
|
||||
|
||||
byte mmc4_RegA;
|
||||
byte mmc4_RegB;
|
||||
byte mmc4_RegC;
|
||||
byte mmc4_RegD;
|
||||
byte mmc4_RegE;
|
||||
byte mmc4_RegF;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG
|
||||
//printf
|
||||
#else
|
||||
#define LOG
|
||||
#endif
|
||||
|
||||
|
||||
void mmc4_MapperWriteRegA(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegA = Value;
|
||||
|
||||
set_prom_bank_16k(0x8000, Value & 0x0F);
|
||||
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegB(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegB = Value;
|
||||
|
||||
set_vrom_bank_4k(0x0000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegC(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegC = Value;
|
||||
set_vrom_bank_4k(0x0000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegD(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegD = Value;
|
||||
set_vrom_bank_4k(0x1000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegE(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegE = Value;
|
||||
set_vrom_bank_4k(0x1000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegF(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegF = Value;
|
||||
if (Value & 0x01)
|
||||
ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
else
|
||||
ppu_setMirroring(PPU_MIRROR_VERTICAL);
|
||||
}
|
||||
|
||||
|
||||
void mmc4_MapperDump(FILE *fp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int mmc4_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0x8000,0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
if (cart->VROMSize > 0)
set_vrom_bank_8k(0x0000,0);
|
||||
|
||||
/* Mapper should register itself for write hook */
|
||||
for (i = 0xA0; i < 0xB0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegA);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xB0; i < 0xC0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegB);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xC0; i < 0xD0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegC);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xD0; i < 0xE0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegD);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xE0; i < 0xF0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegE);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xF0; i < 0x100 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegF);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
for (i = 0x60; i < 0x80 ; i++)
|
||||
{
|
||||
set_page_writeable(i, true);
|
||||
set_page_readable(i, true);
|
||||
}
|
||||
|
||||
//ppu_setScreenMode(PPU_SCMODE_NORMAL);
|
||||
//ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
51
src/mappersmanager/mappers/temp/unrom.c
Executable file
51
src/mappersmanager/mappers/temp/unrom.c
Executable file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* UNROM Mapper - The TI-NESulator Project
|
||||
* unrom.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/unrom.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned char unrom_load_vbank;
|
||||
|
||||
void unrom_MapperWriteHook(register byte Addr, register byte Value);
|
||||
|
||||
int unrom_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0xC000, 0);
|
||||
set_prom_bank_16k(0x8000, GETLAST16KBANK(cart)); /* Set the last one */
|
||||
|
||||
if (Cart->VROMSize > 0)
|
||||
set_vrom_bank_8k(0x0000,0);
|
||||
|
||||
unrom_load_vbank = 0;
|
||||
|
||||
/* Register the write hook */
|
||||
for (i = 0x80; i < 0x100; i++)
|
||||
{
|
||||
set_page_wr_hook(i, unrom_MapperWriteHook);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void unrom_MapperWriteHook(register byte Addr, register byte Value)
|
||||
{
|
||||
set_vrom_bank_8k(0x0000,Value);
|
||||
unrom_load_vbank = Value;
|
||||
}
|
||||
|
||||
void unrom_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"unrom: vbank:%d\n",unrom_load_vbank);
|
||||
}
|
||||
20
src/mappersmanager/mappers_list.h
Normal file
20
src/mappersmanager/mappers_list.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* mappers_list.h
|
||||
* TI-NESulator.X
|
||||
*
|
||||
* Created by Manoël Trapier on 25/10/07.
|
||||
* Copyright 2007 986 Corp. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This file could be generated from the mappers directory... */
|
||||
#include "mappers/norom.h"
|
||||
#include "mappers/mmc1.h"
|
||||
|
||||
Mapper Mappers[] = {
|
||||
{ 0, "No Mapper", norom_InitMapper, norom_MapperIRQ, norom_MapperDump },
|
||||
{ 1, "MMC1", mmc1_InitMapper, norom_MapperIRQ, mmc1_MapperDump },
|
||||
|
||||
/* EOL tag */
|
||||
{ 0, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
63
src/mappersmanager/unused/aorom.h
Executable file
63
src/mappersmanager/unused/aorom.h
Executable file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* AOROM Mapper - The TI-NESulator Project
|
||||
* aorom.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-26 18:47:34 +0200 (jeu, 26 avr 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/aorom.h $
|
||||
* $Revision: 46 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned char aorom_load_bank;
|
||||
|
||||
void aorom_MapperWriteHook(register byte Addr, register byte Value);
|
||||
|
||||
extern byte *ppu_mem_nameTables;
|
||||
|
||||
int aorom_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_32k(0x8000,0);
|
||||
|
||||
ppu_setScreenMode(PPU_SCMODE_SINGLE);
|
||||
|
||||
aorom_load_bank = 0;
|
||||
|
||||
/* Register the write hook */
|
||||
for (i = 0x80; i < 0x100; i++)
|
||||
{
|
||||
set_page_wr_hook(i, aorom_MapperWriteHook);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void aorom_MapperWriteHook(register byte Addr, register byte Value)
|
||||
{
|
||||
int BankNb;
|
||||
|
||||
if (Value & (1 << 4))
|
||||
ppu_setSingleScreen(PPU_SCREEN_000);
|
||||
else
|
||||
ppu_setSingleScreen(PPU_SCREEN_400);
|
||||
|
||||
BankNb = Value & 0x0F;
|
||||
|
||||
aorom_load_bank = BankNb;
|
||||
|
||||
//printf("aorom: Asking bank %d (giving %d & %d) - mirror is %d\n",BankNb,BankNb,(Value<<1)+1,Value&0x0F);
|
||||
set_prom_bank_32k(0x8000,BankNb);
|
||||
}
|
||||
|
||||
void aorom_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"aorom: bank:%d\n",aorom_load_bank);
|
||||
}
|
||||
47
src/mappersmanager/unused/cnrom.h
Executable file
47
src/mappersmanager/unused/cnrom.h
Executable file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* CNROM Mapper - The TI-NESulator Project
|
||||
* cnrom.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/cnrom.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned char cnrom_load_bank;
|
||||
|
||||
void cnrom_MapperWriteHook(register byte Addr, register byte Value);
|
||||
|
||||
int cnrom_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0x8000, 0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart)); /* Set the last one */
|
||||
cnrom_load_bank = 0;
|
||||
|
||||
/* Register the write hook */
|
||||
for (i = 0x80; i < 0x100; i++)
|
||||
{
|
||||
set_page_wr_hook(i, cnrom_MapperWriteHook);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void cnrom_MapperWriteHook(register byte Addr, register byte Value)
|
||||
{
|
||||
set_prom_bank_16k(0x8000,Value);
|
||||
cnrom_load_bank = Value;
|
||||
}
|
||||
|
||||
void cnrom_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"cnrom: bank:%d\n",cnrom_load_bank);
|
||||
}
|
||||
35
src/mappersmanager/unused/genericmapper.h
Executable file
35
src/mappersmanager/unused/genericmapper.h
Executable file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Generic mapper implementation - The TI-NESulator Project
|
||||
* genericmapper.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/genericmapper.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
int _InitMapper(NesCart * cart)
|
||||
{
|
||||
|
||||
set_prom_bank_16k(0xC000,0);
|
||||
set_prom_bank_16k(0x8000,-1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int _MapperWriteHook(register word Addr, register byte Value)
|
||||
{
|
||||
|
||||
if (Addr > 0x7FFF) /* Try to write to the rom */
|
||||
{
|
||||
set_vrom_bank_8k(0x0000,Value)
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
125
src/mappersmanager/unused/iremh3001.h
Executable file
125
src/mappersmanager/unused/iremh3001.h
Executable file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* IREMH3001 Mapper - The TI-NESulator Project
|
||||
* iremh3001.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/iremh3001.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned short iremh3001_prom_slot[3];
|
||||
|
||||
unsigned short iremh3001_vrom_slot[8];
|
||||
|
||||
int iremh3001_InitMapper(NesCart * cart)
|
||||
{
|
||||
|
||||
set_prom_bank_16k(0x8000, 0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
iremh3001_prom_slot[0] = 0;
|
||||
iremh3001_prom_slot[1] = 1;
|
||||
iremh3001_prom_slot[2] = GETLAST16KBANK(cart);
|
||||
|
||||
set_vrom_bank_8k(0x0000,4);
|
||||
|
||||
iremh3001_vrom_slot[0] = 0;
|
||||
iremh3001_vrom_slot[1] = 0;
|
||||
iremh3001_vrom_slot[2] = 0;
|
||||
iremh3001_vrom_slot[3] = 0;
|
||||
iremh3001_vrom_slot[4] = 0;
|
||||
iremh3001_vrom_slot[5] = 0;
|
||||
iremh3001_vrom_slot[6] = 0;
|
||||
iremh3001_vrom_slot[7] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int iremh3001_MapperWriteHook(register word Addr, register byte Value)
|
||||
{
|
||||
|
||||
switch(Addr)
|
||||
{
|
||||
case 0x8000: /* Set 8k PROM @ 8000 */
|
||||
printf("iremh3001: %X: change PROM to %d[%X]\n", Addr, Value, Value);
|
||||
set_prom_bank_8k(0x8000, Value);
|
||||
iremh3001_prom_slot[0] = Value;
|
||||
break;
|
||||
|
||||
case 0x9003: /* Mirroring ??? */
|
||||
printf("iremh3001: Mirroring[0x%X:%d] ?\n", Value, Value);
|
||||
break;
|
||||
|
||||
case 0x9005: /* IRQ ??? */
|
||||
printf("iremh3001: IRQ[0x%X:%d] ?\n", Value, Value);
|
||||
break;
|
||||
|
||||
case 0x9006: /* IRQ ??? */
|
||||
printf("iremh3001: IRQ[0x%X:%d] ?\n", Value, Value);
|
||||
break;
|
||||
|
||||
case 0xA000: /* Set 8k PROM @ A000 */
|
||||
printf("iremh3001: %X: change PROM to %d[%X]\n", Addr, Value, Value);
|
||||
set_prom_bank_8k(0xA000, Value);
|
||||
iremh3001_prom_slot[1] = Value;
|
||||
break;
|
||||
|
||||
case 0xB000: /* Set 1k VROM @ 0000 */
|
||||
case 0xB001: /* Set 1k VROM @ 0400 */
|
||||
case 0xB002: /* Set 1k VROM @ 0800 */
|
||||
case 0xB003: /* Set 1k VROM @ 0C00 */
|
||||
case 0xB004: /* Set 1k VROM @ 1000 */
|
||||
case 0xB005: /* Set 1k VROM @ 1400 */
|
||||
case 0xB006: /* Set 1k VROM @ 1800 */
|
||||
case 0xB007: /* Set 1k VROM @ 1C00 */
|
||||
printf("iremh3001: %X: change VROM to %d[%X]\n", (Addr&0x0F)<<10, Value, Value);
|
||||
set_vrom_bank_1k((Addr&0xF)<<10, Value);
|
||||
iremh3001_vrom_slot[Addr&0x0F] = Value;
|
||||
break;
|
||||
|
||||
case 0xC000: /* Set 8k PROM @ C000 */
|
||||
printf("iremh3001: %X: change PROM to %d[%X]\n", Addr, Value, Value);
|
||||
set_prom_bank_8k(0xC000, Value);
|
||||
iremh3001_prom_slot[2] = Value;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("@:%X -- V:%X", Addr, Value);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void iremh3001_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"iremh3001: prom: $8000:%d $A000:%d $C000:%d\n",
|
||||
iremh3001_prom_slot[0],
|
||||
iremh3001_prom_slot[1],
|
||||
iremh3001_prom_slot[2]);
|
||||
|
||||
fprintf(fp,"iremh3001: vrom: $0000:%d $0400:%d $0800:%d $0C00:%d\n" \
|
||||
" $1000:%d $1400:%d $1800:%d $1C00:%d\n",
|
||||
iremh3001_vrom_slot[0],
|
||||
iremh3001_vrom_slot[1],
|
||||
iremh3001_vrom_slot[2],
|
||||
iremh3001_vrom_slot[3],
|
||||
iremh3001_vrom_slot[4],
|
||||
iremh3001_vrom_slot[5],
|
||||
iremh3001_vrom_slot[6],
|
||||
iremh3001_prom_slot[7]);
|
||||
}
|
||||
|
||||
|
||||
int iremh3001_MapperIRQ(int cycledone)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
355
src/mappersmanager/unused/mmc1.h
Executable file
355
src/mappersmanager/unused/mmc1.h
Executable file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* MMC1 Mapper - The TI-NESulator Project
|
||||
* mmc1.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-02 18:37:41 +0200 (mer, 02 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/mmc1.h $
|
||||
* $Revision: 50 $
|
||||
*
|
||||
*/
|
||||
unsigned char MMC1_reg0;
|
||||
|
||||
unsigned char MMC1_reg1;
|
||||
|
||||
unsigned char MMC1_reg2;
|
||||
|
||||
unsigned char MMC1_reg3;
|
||||
|
||||
unsigned char mmc1_CurrentBank;
|
||||
|
||||
#define MMC1_R0_MIRROR 0x01
|
||||
#define MMC1_R0_ONESCREEN 0x02
|
||||
#define MMC1_R0_PRGAREA 0x04
|
||||
#define MMC1_R0_PRGSIZE 0x08
|
||||
#define MMC1_R0_VROMSW 0x10
|
||||
#define MMC1_R0_RESET 0x80
|
||||
|
||||
#define MMC1_R1_VROMB1 0x0F
|
||||
#define MMC1_R1_256KSEL 0x10
|
||||
#define MMC1_R1_RESET 0x80
|
||||
|
||||
#define MMC1_R2_VROMB2 0x0F
|
||||
#define MMC1_R2_256KSEL 0x10
|
||||
#define MMC1_R2_RESET 0x80
|
||||
|
||||
#define MMC1_R3_VROMB2 0x0F
|
||||
#define MMC1_R3_SAVECE 0x10
|
||||
#define MMC1_R3_RESET 0x80
|
||||
|
||||
|
||||
#define MMC1_REG0_DEFAULT MMC1_R0_PRGSIZE | MMC1_R0_PRGAREA
|
||||
#define MMC1_REG1_DEFAULT 0
|
||||
#define MMC1_REG2_DEFAULT 0
|
||||
#define MMC1_REG3_DEFAULT 0
|
||||
|
||||
|
||||
void mmc1_MapperWriteReg0(register byte Addr, register byte Value);
|
||||
void mmc1_MapperWriteReg1(register byte Addr, register byte Value);
|
||||
void mmc1_MapperWriteReg2(register byte Addr, register byte Value);
|
||||
void mmc1_MapperWriteReg3(register byte Addr, register byte Value);
|
||||
|
||||
void mmc1_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"MMC1: r0:0x%02X r1:0x%02X r2:0x%02X r3:0x%02X\n",MMC1_reg0,MMC1_reg1,MMC1_reg2,MMC1_reg3);
|
||||
}
|
||||
|
||||
int mmc1_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
MMC1_reg0 = MMC1_REG0_DEFAULT;
|
||||
|
||||
MMC1_reg1 = MMC1_REG1_DEFAULT;
|
||||
|
||||
MMC1_reg2 = MMC1_REG2_DEFAULT;
|
||||
|
||||
MMC1_reg3 = MMC1_REG3_DEFAULT;
|
||||
|
||||
set_prom_bank_16k(0x8000,0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
mmc1_CurrentBank = 0;
|
||||
|
||||
if (cart->VROMSize > 0)
|
||||
set_vrom_bank_4k(0x0000,0);
|
||||
|
||||
|
||||
/* Mapper should register itself for write hook */
|
||||
for (i = 0x80; i < 0xA0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg0);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xA0; i < 0xC0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg1);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xC0; i < 0xE0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg2);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xE0; i < 0x100 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc1_MapperWriteReg3);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Reg 0
|
||||
8 : 1000
|
||||
9 : 1001
|
||||
|
||||
Reg 1
|
||||
A : 1010
|
||||
B : 1011
|
||||
|
||||
Reg 2
|
||||
C : 1100
|
||||
D : 1101
|
||||
|
||||
Reg 3
|
||||
E : 1110
|
||||
F : 1111
|
||||
|
||||
((Addr & 0x6000) >> 13) <- port number
|
||||
*/
|
||||
#define MMC1_GetReg(a) ((a & 0x6000) >> 13)
|
||||
/* (Val & 0x01) recuperation du bit */
|
||||
#define MMC1_GetBit(v) (v & 0x01)
|
||||
/* ( ( b & (1 << Bit)) | (v << Bit) ) Ajout du bit */
|
||||
#define MMC1_AddBit(b,v) ( ( b & ~(1 << Bit)) | (v << Bit) )
|
||||
|
||||
void mmc1_ApplyReg0Mod()
|
||||
{
|
||||
|
||||
static unsigned char OldSwitchArea = MMC1_R0_PRGAREA;
|
||||
|
||||
|
||||
|
||||
//printf("Change to reg0 done ! (0x%x)\n\tMiror flag : %d\n\tOneScreen Flag : %d\n\tPRG Size : %d\n\tPRG Area : %d\n\tVROM Switch size : %d\n", MMC1_reg0, MMC1_reg0 & MMC1_R0_MIRROR, MMC1_reg0 & MMC1_R0_ONESCREEN, MMC1_reg0 & MMC1_R0_PRGAREA, MMC1_reg0 & MMC1_R0_PRGSIZE, MMC1_reg0 & MMC1_R0_VROMSW);
|
||||
|
||||
switch (MMC1_reg0 & 0x03)
|
||||
{
|
||||
case 0:
|
||||
ppu_setScreenMode(PPU_SCMODE_SINGLE);
|
||||
ppu_setSingleScreen(PPU_SCREEN_000);
|
||||
break;
|
||||
case 1:
|
||||
ppu_setScreenMode(PPU_SCMODE_SINGLE);
|
||||
ppu_setSingleScreen(PPU_SCREEN_400);
|
||||
break;
|
||||
case 2:
|
||||
ppu_setScreenMode(PPU_SCMODE_NORMAL);
|
||||
ppu_setMirroring(PPU_MIRROR_VERTICAL);
|
||||
break;
|
||||
case 3:
|
||||
ppu_setScreenMode(PPU_SCMODE_NORMAL);
|
||||
ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (OldSwitchArea != (MMC1_reg0 & MMC1_R0_PRGAREA)) && ((MMC1_reg0 & MMC1_R0_PRGSIZE) != 0 ) )
|
||||
{
|
||||
|
||||
if ((MMC1_reg0 & MMC1_R0_PRGAREA) != 0)
|
||||
{ /* 0x8000 area */
|
||||
set_prom_bank_16k(0x8000,mmc1_CurrentBank);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(Cart));
|
||||
}
|
||||
else
|
||||
{ /* 0xC000 area */
|
||||
|
||||
set_prom_bank_16k(0x8000,0);
|
||||
set_prom_bank_16k(0xC000,mmc1_CurrentBank);
|
||||
|
||||
}
|
||||
|
||||
OldSwitchArea = (MMC1_reg0 & MMC1_R0_PRGAREA);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int VROMBankNb;
|
||||
unsigned char Bit = 0;
|
||||
unsigned char BitBuf = 0;
|
||||
|
||||
void mmc1_MapperWriteReg0(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg0 = MMC1_REG0_DEFAULT;
|
||||
printf("MMC1: Reg0 Reset occured !\n");
|
||||
mmc1_ApplyReg0Mod();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg0 = BitBuf;
|
||||
|
||||
mmc1_ApplyReg0Mod();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mmc1_MapperWriteReg1(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg1 = MMC1_REG1_DEFAULT;
|
||||
printf("MMC1: Reg1 Reset occured !\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg1 = BitBuf;
|
||||
|
||||
VROMBankNb = (MMC1_reg1 /* & MMC1_R1_VROMB1 */ );
|
||||
|
||||
if (Cart->VROMSize == 0)
|
||||
{
|
||||
printf("Try to change VROM but with didn't have any VROM ! [%04X]\n", VROMBankNb);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (MMC1_reg0 & MMC1_R0_VROMSW) != 0 )
|
||||
{ /* 4K vram */
|
||||
//printf("Switching VROM at 0x0000 to 4k bank %d\n", VROMBankNb);
|
||||
set_vrom_bank_4k(0x0000,VROMBankNb);
|
||||
}
|
||||
else
|
||||
{ /* 8K vram */
|
||||
//printf("Switching VROM at 0x0000 to 8k bank %d\n", VROMBankNb>>1);
|
||||
set_vrom_bank_8k(0x0000,VROMBankNb>>1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mmc1_MapperWriteReg2(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg2 = MMC1_REG2_DEFAULT;
|
||||
printf("MMC1: Reg2 Reset occured !\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg2 = BitBuf;
|
||||
|
||||
VROMBankNb = (MMC1_reg2 /* & MMC1_R2_VROMB2 */ );
|
||||
|
||||
//printf("Want to switch VROM at 0x1000 to 4k bank %d\n", VROMBankNb);
|
||||
if (Cart->VROMSize == 0)
|
||||
{
|
||||
//printf(": No\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (MMC1_reg0 & MMC1_R0_VROMSW) != 0 )
|
||||
{ /* 4K vram */
|
||||
//printf("Switching VROM at 0x1000 to 4k bank %d\n", VROMBankNb);
|
||||
set_vrom_bank_4k(0x1000,VROMBankNb);
|
||||
}
|
||||
else
|
||||
{ /* 8K vram */
|
||||
// printf("Switching VROM at 0x1000 to 8k bank %d\n", VROMBankNb>>1);
|
||||
// set_vrom_bank_8k(0x1000,VROMBankNb>>1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mmc1_MapperWriteReg3(register byte Addr, register byte Value)
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
MMC1_reg3 = MMC1_REG3_DEFAULT;
|
||||
printf("MMC1: Reg3 Reset occured !\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Bit < 4)
|
||||
{ /* Pas encore ecrit les 5 bits */
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BitBuf = MMC1_AddBit(BitBuf, MMC1_GetBit(Value));
|
||||
Bit = 0;
|
||||
|
||||
MMC1_reg3 = BitBuf;
|
||||
|
||||
if (MMC1_reg3<<14 > Cart->PROMSize)
|
||||
return;
|
||||
|
||||
if ( (MMC1_reg0 & MMC1_R0_PRGSIZE) != 0 )
|
||||
{ /* 16K Switch */
|
||||
if ( (MMC1_reg0 & MMC1_R0_PRGAREA) != 0 )
|
||||
{ /* 0x8000 switch */
|
||||
set_prom_bank_16k(0x8000,MMC1_reg3);
|
||||
//printf("LowBank is now %d ( 0x%p )\n", MMC1_reg3, mLBank);
|
||||
}
|
||||
else
|
||||
{ /* 0xC000 switch */
|
||||
set_prom_bank_16k(0xC000,MMC1_reg3);
|
||||
//printf("HighBank is now %d ( 0x%p )\n", MMC1_reg3, mUBank);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* 32K Switch */
|
||||
set_prom_bank_32k(0x8000,MMC1_reg3>>1);
|
||||
}
|
||||
|
||||
if ( ( MMC1_reg3 & MMC1_R3_SAVECE ) != 0)
|
||||
{
|
||||
unmap_sram();
|
||||
}
|
||||
else
|
||||
{
|
||||
map_sram();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("MMC1: Debug (Reg:%d,Val:0x%02X,reg0:0x%02X,reg1:0x%02X,reg2:0x%02X,reg3:0x%02X)\n", MMC1_GetReg(Addr), Value, MMC1_reg0, MMC1_reg1, MMC1_reg2, MMC1_reg3);
|
||||
317
src/mappersmanager/unused/mmc3.h
Executable file
317
src/mappersmanager/unused/mmc3.h
Executable file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* MMC3 Mapper - The TI-NESulator Project
|
||||
* mmc3.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-02 18:37:41 +0200 (mer, 02 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/mmc3.h $
|
||||
* $Revision: 50 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned short mmc3_command;
|
||||
|
||||
unsigned char mmc3_irq_counter;
|
||||
unsigned char mmc3_irq_counter_reload;
|
||||
unsigned char mmc3_irq_enable;
|
||||
|
||||
unsigned short mmc3_first_prom_page;
|
||||
unsigned short mmc3_second_prom_page;
|
||||
|
||||
unsigned char mmc3_use_xor;
|
||||
unsigned char mmc3_last_vrom[6];
|
||||
|
||||
unsigned char mmc3_last_prom[2];
|
||||
unsigned char mmc3_last_prom_switch;
|
||||
|
||||
unsigned short dummy;
|
||||
|
||||
void mmc3_MapperWrite80Hook(byte addr, byte value);
|
||||
void mmc3_MapperWriteA0Hook(byte addr, byte value);
|
||||
void mmc3_MapperWriteC0Hook(byte addr, byte value);
|
||||
void mmc3_MapperWriteE0Hook(byte addr, byte value);
|
||||
|
||||
void mmc3_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"MMC3: CMD:%d IC:%d IR:%d IE:%d FPP:0x%04X SPP:0x%04X UX:%d\n",mmc3_command,mmc3_irq_counter,mmc3_irq_counter_reload,mmc3_irq_enable,mmc3_first_prom_page,mmc3_second_prom_page,mmc3_use_xor);
|
||||
fprintf(fp,"MMC3: LV0:%d LV1:%d LV2:%d LV3:%d LV4:%d LV5:%d\n",mmc3_last_vrom[0],mmc3_last_vrom[1],mmc3_last_vrom[2],mmc3_last_vrom[3],mmc3_last_vrom[4],mmc3_last_vrom[5]);
|
||||
fprintf(fp,"MMC3: LP0:%d LP1:%d LPS:%d\n",mmc3_last_prom[0],mmc3_last_prom[1],mmc3_last_prom_switch);
|
||||
}
|
||||
|
||||
int mmc3_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0x8000, 0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
if ( Cart->VROMSize > 0)
|
||||
{
|
||||
set_vrom_bank_8k(0, 0x0000);
|
||||
}
|
||||
|
||||
mmc3_command = -1;
|
||||
|
||||
mmc3_irq_counter = -1;
|
||||
mmc3_irq_enable = 1;
|
||||
mmc3_irq_counter_reload = 0;
|
||||
|
||||
mmc3_use_xor = 0x42;
|
||||
|
||||
mmc3_last_prom_switch = 0x42;
|
||||
|
||||
mmc3_last_prom[0] = 0;
|
||||
mmc3_last_prom[1] = 1;
|
||||
|
||||
mmc3_last_vrom[0] = 0;
|
||||
mmc3_last_vrom[1] = 2;
|
||||
mmc3_last_vrom[2] = 3;
|
||||
mmc3_last_vrom[3] = 4;
|
||||
mmc3_last_vrom[4] = 5;
|
||||
mmc3_last_vrom[5] = 6;
|
||||
|
||||
mmc3_first_prom_page = 0x8000;
|
||||
mmc3_second_prom_page = 0xA000;
|
||||
//mmc3_first_prom_page = 0; // Set it to 0x8000
|
||||
|
||||
|
||||
/* Register mapper write hook */
|
||||
set_page_wr_hook(0x80, mmc3_MapperWrite80Hook);
|
||||
set_page_writeable(0x80, true);
|
||||
|
||||
set_page_wr_hook(0xA0, mmc3_MapperWriteA0Hook);
|
||||
set_page_writeable(0xA0, true);
|
||||
|
||||
set_page_wr_hook(0xC0, mmc3_MapperWriteC0Hook);
|
||||
set_page_writeable(0xC0, true);
|
||||
|
||||
set_page_wr_hook(0xE0, mmc3_MapperWriteE0Hook);
|
||||
set_page_writeable(0xE0, true);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void mmc3_MapperWrite80Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
|
||||
if ((Cart->VROMSize > 0) && ( mmc3_use_xor != (Value & 0x80) ))
|
||||
{
|
||||
if (Value & 0x80)
|
||||
{
|
||||
set_vrom_bank_1k(0x0000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x0400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x0800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x0C00, mmc3_last_vrom[5]);
|
||||
set_vrom_bank_2k(0x1000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x1800, mmc3_last_vrom[1]>>1);
|
||||
//chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1
|
||||
}
|
||||
else
|
||||
{
|
||||
set_vrom_bank_2k(0x0000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x0800, mmc3_last_vrom[1]>>1);
|
||||
set_vrom_bank_1k(0x1000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x1400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x1800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x1C00, mmc3_last_vrom[5]);
|
||||
//chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7
|
||||
}
|
||||
mmc3_use_xor = (Value & 0x80);
|
||||
}
|
||||
|
||||
|
||||
if (mmc3_last_prom_switch != (Value & 0x40))
|
||||
{
|
||||
if (!(Value & 0x40))
|
||||
{
|
||||
printf("MMC3: Switch -> 8/A\n");
|
||||
mmc3_first_prom_page = 0x8000;
|
||||
mmc3_second_prom_page = 0xA000;
|
||||
|
||||
set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
|
||||
set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
|
||||
|
||||
set_prom_bank_8k(0xC000, GETLAST08KBANK(Cart)-1);
|
||||
//set_prom_bank_8k(0xE000, GETLAST08KBANK(cart));
|
||||
//prg_bank(prg0,prg1,max_prg-1,max_prg);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("MMC3: Switch -> C/A\n");
|
||||
mmc3_first_prom_page = 0xC000;
|
||||
mmc3_second_prom_page = 0xA000;
|
||||
|
||||
set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
|
||||
set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
|
||||
|
||||
set_prom_bank_8k(0x8000, GETLAST08KBANK(Cart)-1);
|
||||
|
||||
|
||||
//prg_bank(max_prg-1,prg1,prg0,max_prg);
|
||||
}
|
||||
mmc3_last_prom_switch = (Value & 0x40);
|
||||
}
|
||||
mmc3_command = Value & 0x07;
|
||||
|
||||
|
||||
|
||||
} else { /* 8001 */
|
||||
switch (mmc3_command)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
if (Cart->VROMSize == 0)
|
||||
return;
|
||||
|
||||
mmc3_last_vrom[mmc3_command] = Value;
|
||||
|
||||
if (mmc3_use_xor)
|
||||
{
|
||||
set_vrom_bank_1k(0x0000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x0400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x0800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x0C00, mmc3_last_vrom[5]);
|
||||
set_vrom_bank_2k(0x1000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x1800, mmc3_last_vrom[1]>>1);
|
||||
//chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1
|
||||
}
|
||||
else
|
||||
{
|
||||
set_vrom_bank_2k(0x0000, mmc3_last_vrom[0]>>1);
|
||||
set_vrom_bank_2k(0x0800, mmc3_last_vrom[1]>>1);
|
||||
set_vrom_bank_1k(0x1000, mmc3_last_vrom[2]);
|
||||
set_vrom_bank_1k(0x1400, mmc3_last_vrom[3]);
|
||||
set_vrom_bank_1k(0x1800, mmc3_last_vrom[4]);
|
||||
set_vrom_bank_1k(0x1C00, mmc3_last_vrom[5]);
|
||||
//chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
mmc3_last_prom[0] = Value;
|
||||
set_prom_bank_8k(mmc3_first_prom_page, mmc3_last_prom[0]);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
mmc3_last_prom[1] = Value;
|
||||
set_prom_bank_8k(mmc3_second_prom_page, mmc3_last_prom[1]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/*if(mmc3_use_xor)
|
||||
chr_bank(chr4,chr5,chr6,chr7,chr01,chr01+1,chr23,chr23+1);
|
||||
else
|
||||
chr_bank(chr01,chr01+1,chr23,chr23+1,chr4,chr5,chr6,chr7);*/
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void mmc3_MapperWriteA0Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
//printf("MMC3: Select mirroring (0xA000) : 0x%X\n",Value);
|
||||
|
||||
if (Value & 0x1)
|
||||
ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
else
|
||||
ppu_setMirroring(PPU_MIRROR_VERTICAL);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("MMC3: SaveRAM Toggle (0xA001) : 0x%X\n",Value);
|
||||
if (Value)
|
||||
map_sram();
|
||||
else
|
||||
unmap_sram();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern unsigned short ScanLine;
|
||||
|
||||
void mmc3_MapperWriteC0Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
mmc3_irq_counter_reload = Value;
|
||||
mmc3_irq_counter = Value;
|
||||
//printf("MMC3 IRQ[%d]: SetIRQ reload to %d\n", ScanLine, Value);
|
||||
|
||||
}else{ /* C001 */
|
||||
//printf("MMC3: New tmp IRQ value (0xC001) : 0x%X\n",Value);
|
||||
//printf("MMC3 IRQ[%d]: Reset IRQ counter to val %d [Value = %d]\n", ScanLine, mmc3_irq_counter_reload, Value);
|
||||
mmc3_irq_counter = Value;
|
||||
}
|
||||
}
|
||||
|
||||
void mmc3_MapperWriteE0Hook(byte addr, byte Value)
|
||||
{
|
||||
//printf("%s(0x%02X, 0x%02X)\n", __func__, addr, Value);
|
||||
if (addr > 0x01)
|
||||
return;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
//printf("MMC3: Writing to 0xE001 : 0x%X\n",Value);
|
||||
//printf("MMC3 IRQ[%d]: IRQ disabled\n", ScanLine);
|
||||
mmc3_irq_enable = 0;
|
||||
//MapperWantIRQ = 1;
|
||||
// Add a way to raise an IRQ
|
||||
|
||||
}else{ /* E001 */
|
||||
//printf("MMC3: Writing to 0xE001 : 0x%X\n",Value);
|
||||
//printf("MMC3: IRQ Enabled (value : %d)\n",mmc3_irq_counter);
|
||||
//printf("MMC3 IRQ[%d]: Enable IRQ\nr", ScanLine);
|
||||
mmc3_irq_enable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int mmc3_MapperIRQ(int cycledone)
|
||||
{
|
||||
if (((cycledone > 0) && (cycledone < 241)) /*&&
|
||||
(ppu.ControlRegister2.b & (PPU_CR2_BGVISIBILITY | PPU_CR2_SPRTVISIBILITY)) == (PPU_CR2_BGVISIBILITY | PPU_CR2_SPRTVISIBILITY)*/)
|
||||
{
|
||||
|
||||
if ((mmc3_irq_counter --) > 0 )return 0;
|
||||
|
||||
|
||||
/* Load next counter position */
|
||||
mmc3_irq_counter = mmc3_irq_counter_reload;
|
||||
|
||||
if (mmc3_irq_enable == 0) return 0;
|
||||
|
||||
mmc3_irq_enable = 0;
|
||||
|
||||
//printf("MMC3 IRQ[%d]: Tick next at %d\n", ScanLine, mmc3_irq_counter_reload);
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
137
src/mappersmanager/unused/mmc4.h
Normal file
137
src/mappersmanager/unused/mmc4.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* MMC4 Mapper - The TI-NESulator Project
|
||||
* mmc4.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-31 18:00:41 +0200 (jeu, 31 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/mmc4.h $
|
||||
* $Revision: 56 $
|
||||
*
|
||||
*/
|
||||
|
||||
byte mmc4_RegA;
|
||||
byte mmc4_RegB;
|
||||
byte mmc4_RegC;
|
||||
byte mmc4_RegD;
|
||||
byte mmc4_RegE;
|
||||
byte mmc4_RegF;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG
|
||||
//printf
|
||||
#else
|
||||
#define LOG
|
||||
#endif
|
||||
|
||||
|
||||
void mmc4_MapperWriteRegA(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegA = Value;
|
||||
|
||||
set_prom_bank_16k(0x8000, Value & 0x0F);
|
||||
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegB(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegB = Value;
|
||||
|
||||
set_vrom_bank_4k(0x0000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegC(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegC = Value;
|
||||
set_vrom_bank_4k(0x0000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegD(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegD = Value;
|
||||
set_vrom_bank_4k(0x1000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegE(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegE = Value;
|
||||
set_vrom_bank_4k(0x1000, Value & 0x1F);
|
||||
}
|
||||
|
||||
void mmc4_MapperWriteRegF(register byte Addr, register byte Value)
|
||||
{
|
||||
LOG("%s(%02X, %02X)\n", __func__, Addr, Value);
|
||||
mmc4_RegF = Value;
|
||||
if (Value & 0x01)
|
||||
ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
else
|
||||
ppu_setMirroring(PPU_MIRROR_VERTICAL);
|
||||
}
|
||||
|
||||
|
||||
void mmc4_MapperDump(FILE *fp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int mmc4_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0x8000,0);
|
||||
set_prom_bank_16k(0xC000, GETLAST16KBANK(cart));
|
||||
|
||||
if (cart->VROMSize > 0)
set_vrom_bank_8k(0x0000,0);
|
||||
|
||||
/* Mapper should register itself for write hook */
|
||||
for (i = 0xA0; i < 0xB0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegA);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xB0; i < 0xC0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegB);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xC0; i < 0xD0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegC);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xD0; i < 0xE0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegD);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xE0; i < 0xF0 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegE);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
for (i = 0xF0; i < 0x100 ; i++)
|
||||
{
|
||||
set_page_wr_hook(i, mmc4_MapperWriteRegF);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
for (i = 0x60; i < 0x80 ; i++)
|
||||
{
|
||||
set_page_writeable(i, true);
|
||||
set_page_readable(i, true);
|
||||
}
|
||||
|
||||
//ppu_setScreenMode(PPU_SCMODE_NORMAL);
|
||||
//ppu_setMirroring(PPU_MIRROR_HORIZTAL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
51
src/mappersmanager/unused/unrom.h
Executable file
51
src/mappersmanager/unused/unrom.h
Executable file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* UNROM Mapper - The TI-NESulator Project
|
||||
* unrom.h
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-04-16 01:55:35 +0200 (lun, 16 avr 2007) $
|
||||
* $Author: godzil $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/unrom.h $
|
||||
* $Revision: 39 $
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned char unrom_load_vbank;
|
||||
|
||||
void unrom_MapperWriteHook(register byte Addr, register byte Value);
|
||||
|
||||
int unrom_InitMapper(NesCart * cart)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_prom_bank_16k(0xC000, 0);
|
||||
set_prom_bank_16k(0x8000, GETLAST16KBANK(cart)); /* Set the last one */
|
||||
|
||||
if (Cart->VROMSize > 0)
|
||||
set_vrom_bank_8k(0x0000,0);
|
||||
|
||||
unrom_load_vbank = 0;
|
||||
|
||||
/* Register the write hook */
|
||||
for (i = 0x80; i < 0x100; i++)
|
||||
{
|
||||
set_page_wr_hook(i, unrom_MapperWriteHook);
|
||||
set_page_writeable(i, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void unrom_MapperWriteHook(register byte Addr, register byte Value)
|
||||
{
|
||||
set_vrom_bank_8k(0x0000,Value);
|
||||
unrom_load_vbank = Value;
|
||||
}
|
||||
|
||||
void unrom_MapperDump(FILE *fp)
|
||||
{
|
||||
fprintf(fp,"unrom: vbank:%d\n",unrom_load_vbank);
|
||||
}
|
||||
118
src/mappersmanager/utils.c
Executable file
118
src/mappersmanager/utils.c
Executable file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Mapper facilities - The TI-NESulator Project
|
||||
* mappers.c
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-31 18:00:41 +0200 (jeu, 31 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/mappers.c $
|
||||
* $Revision: 56 $
|
||||
*
|
||||
*/
|
||||
|
||||
//#define DEBUG_VROM_BANK_SWITCH
|
||||
//#define DEBUG_PROM_BANK_SWITCH
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <NESCarts.h>
|
||||
#include <ppu/ppu.h>
|
||||
#include <mappers/manager.h>
|
||||
#include <memory/manager.h>
|
||||
|
||||
extern NesCart *Cart;
|
||||
|
||||
extern char MapperWantIRQ;
|
||||
|
||||
/*
|
||||
Here are some fonction useful for mappers
|
||||
*/
|
||||
|
||||
void set_vrom_bank_1k(unsigned short addr,int slot)
|
||||
{
|
||||
#ifdef DEBUG_VROM_BANK_SWITCH
|
||||
printf("Change vrom 1k bank 0x%X to slot %d\n",addr,slot);
|
||||
#endif
|
||||
ppu_setPagePtr1k((addr>>8)&0xFF, Cart->VROMBanks + (slot * 1024));
|
||||
// memcpy(ppu.Memory+addr, Cart->VROMBanks + (slot * 1024), 0x0400);
|
||||
}
|
||||
|
||||
void set_vrom_bank_2k(unsigned short addr,int slot)
|
||||
{
|
||||
#ifdef DEBUG_VROM_BANK_SWITCH
|
||||
printf("Change vrom 2k bank 0x%X to slot %d\n",addr,slot);
|
||||
#endif
|
||||
ppu_setPagePtr2k((addr>>8)&0xFF, Cart->VROMBanks + (slot * 2 * 1024));
|
||||
// memcpy(ppu.Memory+addr, Cart->VROMBanks + (slot * 2 * 1024), 0x0800);
|
||||
}
|
||||
|
||||
void set_vrom_bank_4k(unsigned short addr,int slot)
|
||||
{
|
||||
#ifdef DEBUG_VROM_BANK_SWITCH
|
||||
printf("Change vrom 4k bank 0x%X to slot %d\n",addr,slot);
|
||||
#endif
|
||||
ppu_setPagePtr4k((addr>>8)&0xFF, Cart->VROMBanks + (slot * 4 * 1024));
|
||||
// memcpy(ppu.Memory+addr, Cart->VROMBanks + (slot * 4 * 1024), 0x1000);
|
||||
}
|
||||
|
||||
void set_vrom_bank_8k(unsigned short addr, int slot)
|
||||
{
|
||||
#ifdef DEBUG_VROM_BANK_SWITCH
|
||||
printf("Change vrom 8k bank 0x%X to slot %d\n",addr,slot);
|
||||
#endif
|
||||
ppu_setPagePtr8k(0x00, Cart->VROMBanks + (slot * 8 * 1024));
|
||||
// memcpy(ppu.Memory, Cart->VROMBanks + (slot * 8 * 1024) , 0x2000);
|
||||
}
|
||||
|
||||
/*-----------*/
|
||||
|
||||
void set_prom_bank_8k(unsigned short addr,int slot)
|
||||
{
|
||||
#ifdef DEBUG_PROM_BANK_SWITCH
|
||||
printf("Change prom 8k bank 0x%X to slot %d\n",addr,slot);
|
||||
#endif
|
||||
set_page_ptr_8k(addr >> 8, Cart->PROMBanks + (slot * 8 * 1024));
|
||||
}
|
||||
|
||||
void set_prom_bank_16k(unsigned short addr,int slot)
|
||||
{
|
||||
#ifdef DEBUG_PROM_BANK_SWITCH
|
||||
printf("Change prom 16k bank @ 0x%X [0x%X] to slot 0x%X\n",addr, addr>>8,slot);
|
||||
#endif
|
||||
set_page_ptr_16k(addr >> 8, Cart->PROMBanks + (slot * 16 * 1024));
|
||||
}
|
||||
|
||||
void set_prom_bank_32k(unsigned short addr,int slot)
|
||||
{ /* addr may not be different from 0x8000 !*/
|
||||
/* Anyway I don't use it */
|
||||
#ifdef DEBUG_PROM_BANK_SWITCH
|
||||
printf("Change prom 32k bank 0x%X to slot %d\n",addr,slot);
|
||||
#endif
|
||||
set_page_ptr_32k(addr >> 8, Cart->PROMBanks + (slot * 32 * 1024));
|
||||
/* set_page_ptr_16k(0x80, Cart->PROMBanks[(slot<<1)]);
|
||||
set_page_ptr_16k(0xC0, Cart->PROMBanks[(slot<<1)+1]);*/
|
||||
}
|
||||
|
||||
|
||||
void map_sram()
|
||||
{
|
||||
int i;
|
||||
for (i = 0x60; i < 0x80; i++)
|
||||
{
|
||||
set_page_readable(i,true);
|
||||
set_page_writeable(i,true);
|
||||
}
|
||||
}
|
||||
|
||||
void unmap_sram()
|
||||
{
|
||||
int i;
|
||||
for (i = 0x60; i < 0x80; i++)
|
||||
{
|
||||
set_page_readable(i,false);
|
||||
set_page_writeable(i,false);
|
||||
}
|
||||
}
|
||||
275
src/memorymanager/memory.c
Executable file
275
src/memorymanager/memory.c
Executable file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 6502 Memory manager - The TI-NESulator Project
|
||||
* memory.c - Taken from the Quick6502 project
|
||||
*
|
||||
* Created by Manoël Trapier on 18/09/06.
|
||||
* Copyright 2003-2007 986 Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-02 18:37:41 +0200 (mer, 02 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/memory.c $
|
||||
* $Revision: 50 $
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "../include/memory/manager.h"
|
||||
|
||||
/* Private structures */
|
||||
|
||||
#define KBYTE * (1024)
|
||||
|
||||
/*
|
||||
* What inside memory manager:
|
||||
*
|
||||
* Table of attributes
|
||||
* Table of original page ptr
|
||||
* Table of moded page ptr
|
||||
*
|
||||
*/
|
||||
|
||||
/* Private data */
|
||||
|
||||
byte *memory_pages[0x100];
|
||||
byte memory_pages_attr[0x100];
|
||||
|
||||
func_rdhook rdh_table[0x100];
|
||||
func_wrhook wrh_table[0x100];
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG(s) s
|
||||
#else
|
||||
#define LOG(s) {}
|
||||
#endif
|
||||
|
||||
/* Public functions */
|
||||
void set_page_ptr(byte page, byte *ptr)
|
||||
{
|
||||
LOG(printf("Set page 0x%X to ptr %p\n", page, ptr));
|
||||
memory_pages[page] = ptr;
|
||||
}
|
||||
|
||||
void set_page_ptr_1k(byte page, byte *ptr)
|
||||
{ /* 1k = 4 * 256 */
|
||||
LOG(printf("Set page(1k) 0x%X to ptr %p\n", page, ptr));
|
||||
memory_pages[page + 0] = ptr;
|
||||
memory_pages[page + 1] = ptr + 0x100;
|
||||
memory_pages[page + 2] = ptr + (0x100 * 2);
|
||||
memory_pages[page + 3] = ptr + (0x100 * 3);
|
||||
}
|
||||
|
||||
void set_page_ptr_2k(byte page, byte *ptr)
|
||||
{
|
||||
LOG(printf("Set page(2k) 0x%X to ptr %p\n", page, ptr));
|
||||
memory_pages[page + 0] = ptr;
|
||||
memory_pages[page + 1] = ptr + 0x100;
|
||||
memory_pages[page + 2] = ptr + (0x100 * 2);
|
||||
memory_pages[page + 3] = ptr + (0x100 * 3);
|
||||
memory_pages[page + 4] = ptr + (0x100 * 4);
|
||||
memory_pages[page + 5] = ptr + (0x100 * 5);
|
||||
memory_pages[page + 6] = ptr + (0x100 * 6);
|
||||
memory_pages[page + 7] = ptr + (0x100 * 7);
|
||||
}
|
||||
|
||||
void set_page_ptr_4k(byte page, byte *ptr)
|
||||
{
|
||||
LOG(printf("Set page(4k) 0x%X to ptr %p\n", page, ptr));
|
||||
set_page_ptr_2k(page, ptr);
|
||||
set_page_ptr_2k(page+((4 KBYTE / 256) / 2), ptr + 2 KBYTE);
|
||||
}
|
||||
|
||||
void set_page_ptr_8k(byte page, byte *ptr)
|
||||
{
|
||||
LOG(printf("Set page(8k) 0x%X to ptr %p\n", page, ptr));
|
||||
set_page_ptr_4k(page, ptr);
|
||||
set_page_ptr_4k(page+((8 KBYTE / 256) / 2), ptr + 4 KBYTE);
|
||||
}
|
||||
|
||||
void set_page_ptr_16k(byte page, byte *ptr)
|
||||
{
|
||||
set_page_ptr_8k(page, ptr);
|
||||
set_page_ptr_8k(page+((16 KBYTE / 256) / 2), ptr + 8 KBYTE);
|
||||
}
|
||||
|
||||
void set_page_ptr_32k(byte page, byte *ptr)
|
||||
{
|
||||
set_page_ptr_16k(page, ptr);
|
||||
set_page_ptr_16k(page+((32 KBYTE / 256) / 2), ptr + 16 KBYTE);
|
||||
}
|
||||
|
||||
byte *get_page_ptr(byte page)
|
||||
{
|
||||
return memory_pages[page];
|
||||
}
|
||||
|
||||
|
||||
/* Functions to set pages attributes */
|
||||
|
||||
void set_page_rd_hook(byte page, func_rdhook func)
|
||||
{
|
||||
if (func == NULL)
|
||||
{
|
||||
memory_pages_attr[page] &= (~ATTR_PAGE_HAVE_RDHOOK);
|
||||
if (memory_pages[page] == (byte *)0x01)
|
||||
memory_pages[page] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memory_pages_attr[page] |= ATTR_PAGE_HAVE_RDHOOK;
|
||||
if (memory_pages[page] == NULL)
|
||||
memory_pages[page] = (byte *)0x01;
|
||||
}
|
||||
|
||||
rdh_table[page] = func;
|
||||
}
|
||||
|
||||
void set_page_wr_hook(byte page, func_wrhook func)
|
||||
{
|
||||
if (func == NULL)
|
||||
{
|
||||
memory_pages_attr[page] &= (~ATTR_PAGE_HAVE_WRHOOK);
|
||||
if (memory_pages[page] == (byte*)0x01)
|
||||
memory_pages[page] = NULL;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
memory_pages_attr[page] |= ATTR_PAGE_HAVE_WRHOOK;
|
||||
if (memory_pages[page] == NULL)
|
||||
memory_pages[page] = (byte *)0x01;
|
||||
}
|
||||
|
||||
wrh_table[page] = func;
|
||||
}
|
||||
|
||||
void set_page_readable(byte page, bool value)
|
||||
{
|
||||
if (value == true)
|
||||
memory_pages_attr[page] |= ATTR_PAGE_READABLE;
|
||||
else
|
||||
memory_pages_attr[page] &= (~ATTR_PAGE_READABLE);
|
||||
}
|
||||
|
||||
void set_page_writeable(byte page, bool value)
|
||||
{
|
||||
if (value == true)
|
||||
memory_pages_attr[page] |= ATTR_PAGE_WRITEABLE;
|
||||
else
|
||||
memory_pages_attr[page] &= (~ATTR_PAGE_WRITEABLE);
|
||||
}
|
||||
|
||||
void set_page_ghost(byte page, bool value, byte ghost)
|
||||
{
|
||||
if (value == true)
|
||||
{
|
||||
memory_pages_attr[page] = memory_pages_attr[ghost];
|
||||
rdh_table[page] = rdh_table[ghost];
|
||||
wrh_table[page] = wrh_table[ghost];
|
||||
memory_pages[page] = memory_pages[ghost];
|
||||
}
|
||||
}
|
||||
|
||||
byte get_page_attributes(byte page)
|
||||
{
|
||||
return memory_pages_attr[page];
|
||||
}
|
||||
|
||||
func_rdhook get_page_rdhook(byte page)
|
||||
{
|
||||
if (memory_pages_attr[page] & ATTR_PAGE_HAVE_RDHOOK)
|
||||
return rdh_table[page];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
func_wrhook get_page_wrhook(byte page)
|
||||
{
|
||||
if (memory_pages_attr[page] & ATTR_PAGE_HAVE_WRHOOK)
|
||||
return wrh_table[page];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
byte ReadMemory(byte page, byte addr)
|
||||
{
|
||||
static byte LastRetByte = 0xA5;
|
||||
byte *page_ptr;
|
||||
byte attributes;
|
||||
LOG(printf("Read @ 0x%X-%X\n", page, addr));
|
||||
/* Est-ce que la page est mappé ? && Est-ce que la page est "readable" ? */
|
||||
if ((page_ptr = memory_pages[page]) &&
|
||||
( (attributes = memory_pages_attr[page]) & ATTR_PAGE_READABLE) )
|
||||
{
|
||||
LOG(printf("Page is non null & readable\n"));
|
||||
if ( attributes & ATTR_PAGE_HAVE_RDHOOK )
|
||||
return ( LastRetByte = rdh_table[page](addr) );
|
||||
else
|
||||
return ( LastRetByte = page_ptr[addr] );
|
||||
}
|
||||
//printf("Trying to read @ 0x%X-%X\n", page, addr);
|
||||
return LastRetByte;
|
||||
}
|
||||
|
||||
void WriteMemory(byte page, byte addr, byte value)
|
||||
{
|
||||
byte *page_ptr;
|
||||
byte attributes;
|
||||
LOG(printf("Write 0x%x @ 0x%X-%X\n", value, page, addr));
|
||||
/* Est-ce que la page est mappé ? && Est-ce que la page est "writable" ? */
|
||||
if ( (page_ptr = memory_pages[page]) &&
|
||||
( (attributes = memory_pages_attr[page]) & ATTR_PAGE_WRITEABLE) )
|
||||
{
|
||||
if ( attributes & ATTR_PAGE_HAVE_WRHOOK )
|
||||
{
|
||||
#ifdef DETECT_BUS_CONFLICT
|
||||
if ((page >= 0x80) && (memory_pages[page][addr] != value))
|
||||
printf("WriteHook: bus conflict at %02X%02X rom:%02X write:%02X\n", page, addr, memory_pages[page][addr], value);
|
||||
#endif
|
||||
wrh_table[page](addr, value);
|
||||
}
|
||||
else
|
||||
page_ptr[addr] = value;
|
||||
}
|
||||
else { printf("Trying to write 0x%X @ 0x%X-%X\n", value, page, addr); }
|
||||
}
|
||||
|
||||
void DumpMemoryState(FILE *fp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0x00; i < 0x100; i++)
|
||||
{
|
||||
fprintf(fp,
|
||||
"Page 0x%02X : [%c%c%c%c%c%c] RdH:%p WrH:%p ptr:%p\n",
|
||||
i,
|
||||
(memory_pages_attr[i]&ATTR_PAGE_HAVE_RDHOOK)?'r':'.',
|
||||
(memory_pages_attr[i]&ATTR_PAGE_HAVE_WRHOOK)?'w':'.',
|
||||
(memory_pages_attr[i]&ATTR_PAGE_READABLE)?'R':'.',
|
||||
(memory_pages_attr[i]&ATTR_PAGE_WRITEABLE)?'W':'.',
|
||||
(memory_pages_attr[i]&ATTR_PAGE_GHOST)?'G':'.',
|
||||
(memory_pages_attr[i]&ATTR_PAGE_MAPPED)?'M':'.',
|
||||
rdh_table[i],
|
||||
wrh_table[i],
|
||||
memory_pages[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void InitMemory()
|
||||
{
|
||||
int page;
|
||||
|
||||
for(page = 0 ; page < 0x100 ; page++)
|
||||
{
|
||||
set_page_ptr(page,NULL);
|
||||
memory_pages_attr[page] = 0x00;
|
||||
}
|
||||
}
|
||||
31
src/os/unix/loadfile.c
Normal file
31
src/os/unix/loadfile.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
/* Map a file in memory */
|
||||
void *LoadFilePtr(char * filename)
|
||||
{
|
||||
int fd;
|
||||
void *RetPtr = NULL;
|
||||
struct stat FileStat;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
|
||||
fstat(fd, &FileStat);
|
||||
|
||||
RetPtr = mmap(NULL, FileStat.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
|
||||
close(fd);
|
||||
|
||||
return RetPtr;
|
||||
}
|
||||
121
src/paddle.c
Executable file
121
src/paddle.c
Executable file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Paddle manager - The TI-NESulator Project
|
||||
* paddle.c
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-02 18:37:41 +0200 (mer, 02 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/paddle.c $
|
||||
* $Revision: 50 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <allegro.h>
|
||||
#include "paddle.h"
|
||||
|
||||
void InitPaddle(Paddle * pdl)
|
||||
{
|
||||
pdl->Bit = 1;
|
||||
pdl->LastWrite = 0;
|
||||
}
|
||||
|
||||
|
||||
void WritePaddle(Paddle *pdl, unsigned char val)
|
||||
{
|
||||
if ((pdl->LastWrite == 1) && (val == 0))
|
||||
InitPaddle(pdl);
|
||||
|
||||
pdl->LastWrite = val;
|
||||
}
|
||||
unsigned char ReadPaddle(Paddle * pdl)
|
||||
{
|
||||
switch (pdl->Bit++)
|
||||
{
|
||||
|
||||
case 1:
|
||||
if (key[KEY_Z])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
if (key[KEY_X])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
||||
if (key[KEY_P])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
|
||||
if (key[KEY_ENTER])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
|
||||
if (key[KEY_UP])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
|
||||
if (key[KEY_DOWN])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 7:
|
||||
|
||||
if (key[KEY_LEFT])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 8:
|
||||
|
||||
if (key[KEY_RIGHT])
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 20:
|
||||
|
||||
return 0x41;
|
||||
|
||||
break;
|
||||
|
||||
case 24:
|
||||
|
||||
pdl->Bit = 1;
|
||||
|
||||
return 0x40;
|
||||
|
||||
default:
|
||||
|
||||
return 0x40;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
return 0x40;
|
||||
|
||||
}
|
||||
136
src/pluginsmanager/manager.c
Normal file
136
src/pluginsmanager/manager.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Plugins manager - The TI-NESulator Project
|
||||
* plugins.c
|
||||
*
|
||||
* Created by Manoel TRAPIER on 02/04/07.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate$
|
||||
* $Author$
|
||||
* $HeadURL$
|
||||
* $Revision$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <plugins/manager.h>
|
||||
|
||||
typedef struct Plugin_
|
||||
{
|
||||
byte *name;
|
||||
|
||||
PluginInit init;
|
||||
PluginDeinit deinit;
|
||||
|
||||
} Plugin;
|
||||
|
||||
typedef struct KeyHandler_
|
||||
{
|
||||
byte key;
|
||||
|
||||
PluginKeypress func;
|
||||
|
||||
struct KeyHandler_ *next;
|
||||
|
||||
} KeyHandler;
|
||||
|
||||
KeyHandler *keyHandlersList = NULL;
|
||||
|
||||
#include "plugins_list.h"
|
||||
|
||||
void plugin_list()
|
||||
{
|
||||
Plugin *ptr = &(Plugins[0]);
|
||||
int i = 1;
|
||||
printf("Available plugins:\n");
|
||||
while(ptr->name != NULL)
|
||||
{
|
||||
printf("%d - %s\n", i, ptr->name);
|
||||
ptr++; i++;
|
||||
}
|
||||
}
|
||||
|
||||
int plugin_load(int id)
|
||||
{
|
||||
Plugin *ptr = &(Plugins[0]);
|
||||
|
||||
for ( ; id == 0 && ptr != NULL; id -- )
|
||||
ptr ++;
|
||||
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
|
||||
return ptr->init();
|
||||
}
|
||||
|
||||
int plugin_unload(int id)
|
||||
{
|
||||
Plugin *ptr = &(Plugins[0]);
|
||||
|
||||
for ( ; id == 0 && ptr != NULL; id -- )
|
||||
ptr ++;
|
||||
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
|
||||
return ptr->deinit();
|
||||
}
|
||||
|
||||
|
||||
/* Available functions for plugins */
|
||||
int plugin_install_keypressHandler(byte key, PluginKeypress func)
|
||||
{
|
||||
KeyHandler *ptr;
|
||||
|
||||
if (keyHandlersList == NULL)
|
||||
{
|
||||
keyHandlersList = (KeyHandler*) malloc(sizeof(KeyHandler));
|
||||
|
||||
keyHandlersList->key = key;
|
||||
keyHandlersList->func = func;
|
||||
keyHandlersList->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = keyHandlersList;
|
||||
|
||||
while(ptr->next != NULL)
|
||||
ptr = ptr->next;
|
||||
|
||||
ptr->next = (KeyHandler*) malloc(sizeof(KeyHandler));
|
||||
|
||||
ptr = ptr->next;
|
||||
|
||||
ptr->key = key;
|
||||
ptr->func = func;
|
||||
ptr->next = NULL;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plugin_remove_keypressHandler(byte key, PluginKeypress func)
|
||||
{ /* actually do nothing, we cant remove plugin online */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Available functions outside of plugins */
|
||||
int plugin_keypress(byte key)
|
||||
{
|
||||
KeyHandler *ptr = keyHandlersList;
|
||||
|
||||
while(ptr != NULL)
|
||||
{
|
||||
if (ptr->key == key)
|
||||
{
|
||||
ptr->func();
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
802
src/pluginsmanager/plugins/gamegenie.c
Normal file
802
src/pluginsmanager/plugins/gamegenie.c
Normal file
@ -0,0 +1,802 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <allegro.h>
|
||||
|
||||
#define __TINES_PLUGINS__
|
||||
#include <plugins/manager.h>
|
||||
|
||||
#include <memory/manager.h>
|
||||
#include <types.h>
|
||||
#include "allegro.h"
|
||||
|
||||
typedef enum gg_States_
|
||||
{
|
||||
GG_S00_MAIN_STATE = 0,
|
||||
GG_S01_SEARCH_VALUE,
|
||||
GG_S02_SEARCH_BAR
|
||||
} gg_States;
|
||||
|
||||
/* Actual State Machine state */
|
||||
gg_States gg_state = GG_S00_MAIN_STATE;
|
||||
|
||||
/* Own representation of memory */
|
||||
byte gg_MainRAM[0x800];
|
||||
byte gg_OldMainRAM[0x800];
|
||||
byte gg_SRAM[0x2000];
|
||||
|
||||
/* Field used to now which byte are currently marked as pertinent or not */
|
||||
byte gg_use_MainRAM[0x800];
|
||||
byte gg_use_SRAM[0x2000];
|
||||
|
||||
int gg_ResultNumber;
|
||||
|
||||
byte gg_PatchUsed[10];
|
||||
byte gg_PatchedPage[10];
|
||||
byte gg_PatchedAddr[10];
|
||||
byte gg_PatchedValue[10];
|
||||
func_rdhook gg_rdhookPtr[10];
|
||||
|
||||
#define GG_RDHOOKPATCH(d) \
|
||||
byte gg_RdHookPatch##d(byte addr) \
|
||||
{ \
|
||||
if (addr == gg_PatchedAddr[d]) \
|
||||
{ \
|
||||
return gg_PatchedValue[d]; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (gg_rdhookPtr[d] != NULL) \
|
||||
return gg_rdhookPtr[d](addr); \
|
||||
else \
|
||||
return (get_page_ptr(gg_PatchedPage[d])[addr]); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GG_MAX_PATCH 10
|
||||
|
||||
/* Defines the rdhook patches */
|
||||
GG_RDHOOKPATCH(0)
|
||||
GG_RDHOOKPATCH(1)
|
||||
GG_RDHOOKPATCH(2)
|
||||
GG_RDHOOKPATCH(3)
|
||||
GG_RDHOOKPATCH(4)
|
||||
GG_RDHOOKPATCH(5)
|
||||
GG_RDHOOKPATCH(6)
|
||||
GG_RDHOOKPATCH(7)
|
||||
GG_RDHOOKPATCH(8)
|
||||
GG_RDHOOKPATCH(9)
|
||||
|
||||
void gg_SetPatch(int id, byte page, byte addr, byte value)
|
||||
{
|
||||
func_rdhook *fptr;
|
||||
|
||||
if (id >= GG_MAX_PATCH)
|
||||
return;
|
||||
|
||||
/* Set parameters for the patch */
|
||||
if (gg_PatchUsed[id] == 0x00)
|
||||
{
|
||||
gg_rdhookPtr[id] = get_page_rdhook(page);
|
||||
}
|
||||
|
||||
gg_PatchedPage[id] = page;
|
||||
gg_PatchedAddr[id] = addr;
|
||||
gg_PatchedValue[id] = value;
|
||||
gg_PatchUsed[id] = 0xFF;
|
||||
|
||||
/* Set a ReadHook on the page */
|
||||
|
||||
switch(id)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
fptr = gg_RdHookPatch0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
fptr = gg_RdHookPatch1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
fptr = gg_RdHookPatch2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fptr = gg_RdHookPatch3;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
fptr = gg_RdHookPatch4;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
fptr = gg_RdHookPatch5;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
fptr = gg_RdHookPatch6;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
fptr = gg_RdHookPatch7;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
fptr = gg_RdHookPatch8;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
fptr = gg_RdHookPatch9;
|
||||
break;
|
||||
}
|
||||
|
||||
set_page_rd_hook(page, fptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Access to the bitmap Buffer */
|
||||
extern BITMAP *Buffer;
|
||||
BITMAP *gg_Buffer;
|
||||
|
||||
void MessageBox(char *title, char *msg)
|
||||
{
|
||||
|
||||
int sc_w, sc_h;
|
||||
int box_h, box_t, box_l, box_w;
|
||||
|
||||
sc_w = screen->w;
|
||||
sc_h = screen->h;
|
||||
|
||||
gg_Buffer = create_bitmap(sc_w, sc_h);
|
||||
|
||||
blit(Buffer, gg_Buffer, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
box_w = text_length(font, title) + 10;
|
||||
|
||||
box_w = (box_w>text_length(font, msg))?box_w:text_length(font, msg);
|
||||
|
||||
box_w += 15 * 2; /*sc_w/2;*/
|
||||
box_h = 15*2 + 10;
|
||||
|
||||
/* Set the box center */
|
||||
box_t = (sc_h - box_h) / 2;
|
||||
box_l = (sc_w - box_w) / 2;
|
||||
|
||||
rectfill(gg_Buffer, box_l, box_t, box_l + box_w, box_t + box_h, 60);
|
||||
rect(gg_Buffer, box_l + 5, box_t + 5, box_l + box_w - 5, box_t + box_h - 5, 34);
|
||||
|
||||
/* Display the title */
|
||||
textout_centre_ex(gg_Buffer, font, title, box_w / 2 + box_l, box_t + 2, 34, 60);
|
||||
|
||||
/* Display the message */
|
||||
textout_centre_ex(gg_Buffer, font, msg, box_w / 2 + box_l, 15 + box_t + 2, 34, 60);
|
||||
|
||||
blit(gg_Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
sleep(1);
|
||||
|
||||
release_bitmap(gg_Buffer);
|
||||
|
||||
}
|
||||
|
||||
unsigned short SelectNumber(char *title, char *msg, byte size)
|
||||
{
|
||||
|
||||
int sc_w, sc_h;
|
||||
int box_h, box_t, box_l, box_w;
|
||||
|
||||
char valueText[10];
|
||||
|
||||
unsigned short value;
|
||||
byte digit = 0;
|
||||
|
||||
sc_w = screen->w;
|
||||
sc_h = screen->h;
|
||||
|
||||
gg_Buffer = create_bitmap(sc_w, sc_h);
|
||||
|
||||
blit(Buffer, gg_Buffer, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
box_w = text_length(font, title) + 10;
|
||||
|
||||
box_w = (box_w>text_length(font, msg))?box_w:text_length(font, msg);
|
||||
|
||||
sprintf(valueText, "0000");
|
||||
|
||||
box_w = (box_w>text_length(font, valueText))?box_w:text_length(font, msg);
|
||||
|
||||
box_w += 15 * 2; /*sc_w/2;*/
|
||||
box_h = 15*2 + 30;
|
||||
|
||||
/* Set the box center */
|
||||
box_t = (sc_h - box_h) / 2;
|
||||
box_l = (sc_w - box_w) / 2;
|
||||
|
||||
|
||||
value = 0;
|
||||
|
||||
while(!key[KEY_ENTER])
|
||||
{
|
||||
|
||||
rectfill(gg_Buffer, box_l, box_t, box_l + box_w, box_t + box_h, 60);
|
||||
rect(gg_Buffer, box_l + 5, box_t + 5, box_l + box_w - 5, box_t + box_h - 5, 34);
|
||||
|
||||
/* Display the title */
|
||||
textout_centre_ex(gg_Buffer, font, title, box_w / 2 + box_l, box_t + 2, 34, 60);
|
||||
|
||||
/* Display the message */
|
||||
textout_centre_ex(gg_Buffer, font, msg, box_w / 2 + box_l, 15 + box_t + 2, 34, 60);
|
||||
|
||||
if (size == 2)
|
||||
sprintf(valueText, " %02X", value&0xFF);
|
||||
else
|
||||
sprintf(valueText, "%04X", value);
|
||||
|
||||
textout_centre_ex(gg_Buffer, font, valueText, box_w / 2 + box_l , 15 + box_t + 2 + 10, 34, 60);
|
||||
|
||||
switch(digit)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
textout_centre_ex(gg_Buffer, font, " ^", box_w / 2 + box_l , 15 + box_t + 2 + 20, 34, 60);
|
||||
break;
|
||||
case 1:
|
||||
textout_centre_ex(gg_Buffer, font, " ^ ", box_w / 2 + box_l , 15 + box_t + 2 + 20, 34, 60);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
textout_centre_ex(gg_Buffer, font, " ^ ", box_w / 2 + box_l , 15 + box_t + 2 + 20, 34, 60);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
textout_centre_ex(gg_Buffer, font, "^ ", box_w / 2 + box_l , 15 + box_t + 2 + 20, 34, 60);
|
||||
break;
|
||||
}
|
||||
|
||||
blit(gg_Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
if (key[KEY_UP])
|
||||
{
|
||||
usleep(100000);
|
||||
value += ((digit==0)?0x0001:((digit==1)?0x0010:((digit==2)?0x0100:0x1000)));
|
||||
value &= (size==2)?0xFF:0xFFFF;
|
||||
}
|
||||
|
||||
if (key[KEY_DOWN])
|
||||
{
|
||||
usleep(100000);
|
||||
value -= ((digit==0)?0x0001:((digit==1)?0x0010:((digit==2)?0x0100:0x1000)));
|
||||
value &= (size==2)?0xFF:0xFFFF;
|
||||
}
|
||||
|
||||
if (key[KEY_RIGHT])
|
||||
{
|
||||
usleep(100000);
|
||||
if (digit <= 0)
|
||||
digit = size-1;
|
||||
else
|
||||
digit --;
|
||||
}
|
||||
|
||||
if (key[KEY_LEFT])
|
||||
{
|
||||
usleep(100000);
|
||||
if (digit >= size-1)
|
||||
digit = 0;
|
||||
else
|
||||
digit ++;
|
||||
}
|
||||
|
||||
}
|
||||
release_bitmap(gg_Buffer);
|
||||
while(key[KEY_ENTER]);
|
||||
return value;
|
||||
}
|
||||
|
||||
int DispMenu(int itemc, char *itemv[], char *title)
|
||||
{
|
||||
//printf("%s(%d, %p, \"%s\");\n", __func__, itemc, itemv, title);
|
||||
|
||||
int selection = 0;
|
||||
int i;
|
||||
int sc_w, sc_h;
|
||||
int box_h, box_t, box_l, box_w;
|
||||
|
||||
sc_w = screen->w;
|
||||
sc_h = screen->h;
|
||||
|
||||
gg_Buffer = create_bitmap(sc_w, sc_h);
|
||||
|
||||
blit(Buffer, gg_Buffer, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
box_w = text_length(font, title) + 10;
|
||||
|
||||
for (i = 0; i < itemc; i ++)
|
||||
box_w = (box_w>text_length(font, itemv[i]))?box_w:text_length(font, itemv[i]);
|
||||
|
||||
box_w += 15 * 2; /*sc_w/2;*/
|
||||
box_h = 15*2 + itemc*10;
|
||||
|
||||
/* Set the box center */
|
||||
box_t = (sc_h - box_h) / 2;
|
||||
box_l = (sc_w - box_w) / 2;
|
||||
|
||||
|
||||
while(!key[KEY_ENTER])
|
||||
{
|
||||
/* Draw the box and highlight the selected item */
|
||||
rectfill(gg_Buffer, box_l, box_t, box_l + box_w, box_t + box_h, 60);
|
||||
rect(gg_Buffer, box_l + 5, box_t + 5, box_l + box_w - 5, box_t + box_h - 5, 34);
|
||||
|
||||
/* Display the title */
|
||||
textout_centre_ex(gg_Buffer, font, title, box_w / 2 + box_l, box_t + 2, 34, 60);
|
||||
|
||||
/* Display the highlight item */
|
||||
rectfill(gg_Buffer, box_l+15, 15 + box_t + (selection * 10) , box_l + box_w - 15, 15 + box_t + (selection * 10) + 10, 34);
|
||||
textout_centre_ex(gg_Buffer, font, itemv[selection], box_w / 2 + box_l, 15 + box_t + (selection * 10) + 2, 60, 34);
|
||||
|
||||
/* Display other items */
|
||||
for (i = 0; i < itemc; i ++)
|
||||
{
|
||||
if (i != selection)
|
||||
textout_centre_ex(gg_Buffer, font, itemv[i], box_w / 2 + box_l, 15 + box_t + (i * 10) + 2, 34, 60);
|
||||
}
|
||||
|
||||
|
||||
/* Blit the screen buffer */
|
||||
blit(gg_Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
/* Now get the keyboard state */
|
||||
if (key[KEY_UP])
|
||||
{
|
||||
usleep(100000);
|
||||
if (selection <= 0)
|
||||
selection = itemc - 1;
|
||||
else
|
||||
selection --;
|
||||
}
|
||||
|
||||
if (key[KEY_DOWN])
|
||||
{
|
||||
usleep(100000);
|
||||
if (selection >= (itemc - 1))
|
||||
selection = 0;
|
||||
else
|
||||
selection ++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
release_bitmap(gg_Buffer);
|
||||
while(key[KEY_ENTER]);
|
||||
return selection;
|
||||
}
|
||||
|
||||
byte AskYesNo(char *title)
|
||||
{
|
||||
char *YesNo[] = { "No", "Yes" };
|
||||
|
||||
return DispMenu(2, YesNo, title);
|
||||
}
|
||||
|
||||
byte gg_CalcChk(unsigned short addr, byte value)
|
||||
{
|
||||
int chk = 0x42;
|
||||
chk += (addr & 0xFF00) >> 8;
|
||||
chk -= (addr & 0x00FF);
|
||||
chk += (value & 0x00FF);
|
||||
return chk;
|
||||
}
|
||||
|
||||
/*
|
||||
Code is AAAAVVCC where
|
||||
AAAA = address,
|
||||
VV = value,
|
||||
CC = cheksum
|
||||
*/
|
||||
unsigned long gg_MakeCode(unsigned addr, byte value)
|
||||
{
|
||||
unsigned long code = addr << 16;
|
||||
code |= (value << 8);
|
||||
code |= (gg_CalcChk(addr, value) & 0x00FF);
|
||||
|
||||
return code ^ 0x246FF53A;
|
||||
}
|
||||
|
||||
byte gg_SelectPatch()
|
||||
{
|
||||
char *Items[GG_MAX_PATCH + 1];
|
||||
char *tmp;
|
||||
int i;
|
||||
byte ret;
|
||||
|
||||
for (i = 0; i < GG_MAX_PATCH; i++)
|
||||
{
|
||||
tmp = (char*) malloc(0x100);
|
||||
printf("Items[%d]: %p\n", i, tmp);
|
||||
if (gg_PatchUsed[i] == 0x00)
|
||||
sprintf(tmp, "Patch %d: Not used", i);
|
||||
else
|
||||
sprintf(tmp, "Patch %d: Put 0x%02X on address 0x%02X%02X (Code: %08X)",
|
||||
i, gg_PatchedValue[i], gg_PatchedPage[i], gg_PatchedAddr[i],
|
||||
gg_MakeCode((gg_PatchedPage[i]<<8) | gg_PatchedAddr[i], gg_PatchedValue[i]));
|
||||
|
||||
Items[i] = tmp;
|
||||
}
|
||||
|
||||
tmp = (char*) malloc(0x100);
|
||||
sprintf(tmp, "Return");
|
||||
Items[GG_MAX_PATCH] = tmp;
|
||||
|
||||
ret = DispMenu(GG_MAX_PATCH + 1, Items, "Code Breaker - Select a patch");
|
||||
|
||||
for(i = 0; i < GG_MAX_PATCH; i++)
|
||||
free(Items[i]);
|
||||
|
||||
if (ret == GG_MAX_PATCH)
|
||||
return 0xFF;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gg_PatchManager()
|
||||
{
|
||||
printf("DTC!\n");
|
||||
}
|
||||
|
||||
void gg_InitSearch()
|
||||
{
|
||||
unsigned short addr;
|
||||
|
||||
for(addr = 0x000; addr < 0x800; addr ++)
|
||||
{
|
||||
gg_MainRAM[addr] = ReadMemory((addr&0xFF00)>>8,addr&0x00FF);
|
||||
gg_use_MainRAM[addr] = 0xFF;
|
||||
}
|
||||
|
||||
gg_ResultNumber = 0x800;
|
||||
}
|
||||
|
||||
typedef enum gg_SearchForMode_
|
||||
{
|
||||
GG_SEARCHFOR_LOWER = 0,
|
||||
GG_SEARCHFOR_HIGHER,
|
||||
GG_SEARCHFOR_IDENTIC,
|
||||
GG_SEARCHFOR_DIFFERENT
|
||||
|
||||
} gg_SearchForMode;
|
||||
|
||||
void gg_SearchForValue(byte value)
|
||||
{
|
||||
unsigned short addr;
|
||||
byte oldValue;
|
||||
byte currentValue;
|
||||
gg_ResultNumber = 0x00;
|
||||
for(addr = 0x000; addr < 0x800; addr ++)
|
||||
{
|
||||
if (gg_use_MainRAM[addr] == 0xFF)
|
||||
{
|
||||
/* "Backup" the old ram */
|
||||
memcpy(gg_OldMainRAM, gg_MainRAM, 0x800);
|
||||
|
||||
oldValue = gg_MainRAM[addr];
|
||||
currentValue = ReadMemory((addr&0xFF00)>>8,addr&0x00FF);
|
||||
|
||||
if (currentValue != value)
|
||||
{ /* This is not the good one ! */
|
||||
gg_use_MainRAM[addr] = 0x00;
|
||||
}
|
||||
else
|
||||
{ /* This can be the good one ! */
|
||||
gg_ResultNumber++;
|
||||
gg_MainRAM[addr] = currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gg_SearchFor(gg_SearchForMode mode)
|
||||
{
|
||||
unsigned short addr;
|
||||
byte oldValue;
|
||||
byte currentValue;
|
||||
gg_ResultNumber = 0x00;
|
||||
for(addr = 0x000; addr < 0x800; addr ++)
|
||||
{
|
||||
if (gg_use_MainRAM[addr] == 0xFF)
|
||||
{
|
||||
/* "Backup" the old ram */
|
||||
memcpy(gg_OldMainRAM, gg_MainRAM, 0x800);
|
||||
|
||||
oldValue = gg_MainRAM[addr];
|
||||
currentValue = ReadMemory((addr&0xFF00)>>8,addr&0x00FF);
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case GG_SEARCHFOR_LOWER:
|
||||
if (currentValue >= oldValue)
|
||||
{ /* This is not the good one ! */
|
||||
gg_use_MainRAM[addr] = 0x00;
|
||||
}
|
||||
else
|
||||
{ /* This can be the good one ! */
|
||||
gg_ResultNumber++;
|
||||
gg_MainRAM[addr] = currentValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case GG_SEARCHFOR_HIGHER:
|
||||
if (currentValue <= oldValue)
|
||||
{ /* This is not the good one ! */
|
||||
gg_use_MainRAM[addr] = 0x00;
|
||||
}
|
||||
else
|
||||
{ /* This can be the good one ! */
|
||||
gg_ResultNumber++;
|
||||
gg_MainRAM[addr] = currentValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case GG_SEARCHFOR_IDENTIC:
|
||||
if (currentValue != oldValue)
|
||||
{ /* This is not the good one ! */
|
||||
gg_use_MainRAM[addr] = 0x00;
|
||||
}
|
||||
else
|
||||
{ /* This can be the good one ! */
|
||||
gg_ResultNumber++;
|
||||
gg_MainRAM[addr] = currentValue;
|
||||
}
|
||||
break;
|
||||
case GG_SEARCHFOR_DIFFERENT:
|
||||
if (currentValue == oldValue)
|
||||
{ /* This is not the good one ! */
|
||||
gg_use_MainRAM[addr] = 0x00;
|
||||
}
|
||||
else
|
||||
{ /* This can be the good one ! */
|
||||
gg_ResultNumber++;
|
||||
gg_MainRAM[addr] = currentValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte gg_DisplayResults()
|
||||
{
|
||||
char *Items[100];
|
||||
char *tmp;
|
||||
int i, addr = 0x0000;
|
||||
byte ret = 0;
|
||||
|
||||
unsigned short AddrList[21];
|
||||
if (gg_ResultNumber > 20)
|
||||
{
|
||||
MessageBox("Code Breaker", "Too many results for displaying them!");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < gg_ResultNumber; i++)
|
||||
{
|
||||
while(gg_use_MainRAM[addr] != 0xFF)
|
||||
addr ++;
|
||||
printf("0x%04X [%d]\n", addr, i);
|
||||
tmp = (char*) malloc(0x100);
|
||||
sprintf(tmp,"Patch: %08XAddress 0x%04X - Was: 0x%02X - Actual: 0x%02X",
|
||||
i,
|
||||
addr,
|
||||
gg_OldMainRAM[addr],
|
||||
gg_MainRAM[addr]);
|
||||
Items[i] = tmp;
|
||||
AddrList[i] = addr;
|
||||
|
||||
addr++;
|
||||
}
|
||||
tmp = (char*) malloc(0x100);
|
||||
sprintf(tmp, "Return");
|
||||
Items[i] = tmp;
|
||||
|
||||
ret = DispMenu(gg_ResultNumber + 1, Items, "Code Breaker - Search");
|
||||
if (ret < i)
|
||||
{
|
||||
if (AskYesNo("Code Breaker: Apply this patch?"))
|
||||
{
|
||||
/* Now patch it ! */
|
||||
gg_SetPatch(gg_SelectPatch(), (AddrList[ret]&0xFF00)>>8, (AddrList[ret]&0x00FF),
|
||||
SelectNumber("Code Breaker", "Value to apply:", 2) & 0x00FF);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0 ; i<gg_ResultNumber+1; i++)
|
||||
free(Items[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gg_Start()
|
||||
{
|
||||
char *S00_MenuList[] = { "Search a specific Value", "Search for an Unknown Value", "Enter code",
|
||||
"Manage Patches", "Exit" };
|
||||
|
||||
char *S01_MenuList[] = { "Value is identical", "New Value...", "Value is different",
|
||||
"Value is greater", "Value is lower", "Result", "Restart", "Exit" };
|
||||
|
||||
char *S02_MenuList[] = { "Value is identical", "Value is different", "Value is greater",
|
||||
"Value is lower", "Result", "Restart", "Exit" };
|
||||
|
||||
char Buffer[100];
|
||||
int ret;
|
||||
byte value;
|
||||
unsigned short addr;
|
||||
switch(gg_state)
|
||||
{
|
||||
default:
|
||||
case GG_S00_MAIN_STATE:
|
||||
ret = DispMenu(5, S00_MenuList, "Code Breaker - Main");
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
|
||||
gg_InitSearch();
|
||||
gg_state = GG_S01_SEARCH_VALUE;
|
||||
value = SelectNumber("Code Breaker", "Select the value:", 2) & 0x00FF;
|
||||
|
||||
gg_SearchForValue(value);
|
||||
|
||||
MessageBox("Code Breaker", "Search initialized !");
|
||||
break;
|
||||
case 1:
|
||||
gg_InitSearch();
|
||||
gg_state = GG_S02_SEARCH_BAR;
|
||||
MessageBox("Code Breaker", "Search initialized !");
|
||||
break;
|
||||
case 2: /* Enter code */
|
||||
addr = SelectNumber("Code Breaker", "Select the address", 4);
|
||||
value = SelectNumber("Code Breaker", "Select the value:", 2) & 0x00FF;
|
||||
|
||||
if (AskYesNo("Code Breaker: Apply this patch?"))
|
||||
{
|
||||
/* Now patch it ! */
|
||||
gg_SetPatch(gg_SelectPatch(),
|
||||
(addr&0xFF00)>>8, (addr&0x00FF),
|
||||
value);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3: /* Patch manager */
|
||||
gg_PatchManager();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case GG_S01_SEARCH_VALUE:
|
||||
S01_MENU:
|
||||
ret = DispMenu(8, S01_MenuList, "Code Breaker - Search");
|
||||
switch(ret)
|
||||
{
|
||||
case 0:
|
||||
gg_SearchFor(GG_SEARCHFOR_IDENTIC);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
case 1:
|
||||
value = SelectNumber("Code Breaker", "Select the value:", 2) & 0x00FF;
|
||||
|
||||
gg_SearchForValue(value);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gg_SearchFor(GG_SEARCHFOR_DIFFERENT);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gg_SearchFor(GG_SEARCHFOR_HIGHER);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
gg_SearchFor(GG_SEARCHFOR_LOWER);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 5: /* Results */
|
||||
if (gg_DisplayResults() == 1)
|
||||
gg_state = GG_S00_MAIN_STATE;
|
||||
else
|
||||
goto S01_MENU;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
if (AskYesNo("Code Breaker: Restart?"))
|
||||
{
|
||||
gg_state = GG_S00_MAIN_STATE;
|
||||
gg_Start();
|
||||
}
|
||||
else
|
||||
goto S01_MENU;
|
||||
break;
|
||||
|
||||
}
|
||||
sprintf(Buffer,"Results found: %d", gg_ResultNumber);
|
||||
MessageBox("Code Breaker", Buffer);
|
||||
|
||||
break;
|
||||
|
||||
case GG_S02_SEARCH_BAR:
|
||||
S02_MENU:
|
||||
ret = DispMenu(7, S02_MenuList, "Code Breaker - Search");
|
||||
switch(ret)
|
||||
{
|
||||
case 0:
|
||||
gg_SearchFor(GG_SEARCHFOR_IDENTIC);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gg_SearchFor(GG_SEARCHFOR_DIFFERENT);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gg_SearchFor(GG_SEARCHFOR_HIGHER);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gg_SearchFor(GG_SEARCHFOR_LOWER);
|
||||
//goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 4: /* Results */
|
||||
if (gg_DisplayResults() == 1)
|
||||
gg_state = GG_S00_MAIN_STATE;
|
||||
else
|
||||
goto S02_MENU;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (AskYesNo("Code Breaker: Restart?"))
|
||||
{
|
||||
gg_state = GG_S00_MAIN_STATE;
|
||||
gg_Start();
|
||||
}
|
||||
else
|
||||
goto S02_MENU;
|
||||
break;
|
||||
|
||||
}
|
||||
sprintf(Buffer,"Results found: %d", gg_ResultNumber);
|
||||
MessageBox("Code Breaker", Buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int gg_Init()
|
||||
{
|
||||
int i;
|
||||
printf("Initializing GG plugin...\n");
|
||||
|
||||
plugin_install_keypressHandler('g', gg_Start);
|
||||
|
||||
for ( i = 0; i < GG_MAX_PATCH; i++)
|
||||
gg_PatchUsed[i] = 0x00;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gg_Deinit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
2
src/pluginsmanager/plugins/gamegenie.h
Normal file
2
src/pluginsmanager/plugins/gamegenie.h
Normal file
@ -0,0 +1,2 @@
|
||||
int gg_Init();
|
||||
int gg_Deinit();
|
||||
10
src/pluginsmanager/plugins_list.h
Normal file
10
src/pluginsmanager/plugins_list.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* This file could be generated from the plugins directory... */
|
||||
|
||||
#include "plugins/gamegenie.h"
|
||||
|
||||
Plugin Plugins[] = {
|
||||
{ "Game Genie", gg_Init, gg_Deinit },
|
||||
|
||||
/* EOL tag */
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
348
src/ppu/debug/ppu.debug.c
Normal file
348
src/ppu/debug/ppu.debug.c
Normal file
@ -0,0 +1,348 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <allegro.h>
|
||||
|
||||
#define __TINES_PPU_INTERNAL__
|
||||
|
||||
#include <ppu/ppu.h>
|
||||
#include <ppu/ppu.memory.h>
|
||||
#include <ppu/ppu.debug.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
extern BITMAP *Buffer;
|
||||
|
||||
extern unsigned short ppu_spritePatternTable;
|
||||
|
||||
extern short PPU_Reg_S;
|
||||
|
||||
void DebugColor()
|
||||
{
|
||||
#ifdef TO_MAKE
|
||||
static unsigned short x = 128;
|
||||
static unsigned short y = 128;
|
||||
unsigned char OldDisplayPalette = ppu.DisplayPalette;
|
||||
byte keyb;
|
||||
unsigned int i;
|
||||
unsigned long Color;
|
||||
|
||||
NOBLIT = 1;
|
||||
|
||||
ppu.DisplayPalette = ~0;
|
||||
|
||||
while(!key[KEY_ESC])
|
||||
{
|
||||
frame++;
|
||||
PPUVBlank();
|
||||
|
||||
Color = /*Buffer->line[y][x]*/ _getpixel(Buffer, x, y);
|
||||
|
||||
textprintf(Buffer, font, 5, 340, GetColor(3), "Pos [%d:%d] Color: %d Bg: %d", x, y, Color, BgColor);
|
||||
|
||||
line(Buffer, x-10, y, x+10, y, GetColor(1));
|
||||
line(Buffer, x, y-10, x, y+10, GetColor(1));
|
||||
|
||||
|
||||
/*
|
||||
rect(Buffer, 0, 255, 4 * 20 + 2, 255 + 4 * 20 + 2, 0);
|
||||
rect(Buffer, 90, 255, 90 + 4 * 20 + 2, 255 + 4 * 20 + 2, 0);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
rectfill(Buffer, 1 + (i % 4) * 20, 256 + (i / 4) * 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, PPU_Rd(0x3F00 + i]);
|
||||
rectfill(Buffer, 91 + (i % 4) * 20, 256 + (i / 4) * 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, PPU_Rd(0x3F10 + i]);
|
||||
}*/
|
||||
for( i = 0; i < 16; i++)
|
||||
{
|
||||
if (GetColor(PPU_Rd(0x3F00 + i]) == Color)
|
||||
{
|
||||
line(Buffer, 1+(i%4)*20, 256 + (i / 4) * 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, 0xFFFFFFFF);
|
||||
line(Buffer, 1+(i%4)*20, 256 + (i / 4) * 20 + 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
if (GetColor(PPU_Rd(0x3F10 + i]) == Color)
|
||||
{
|
||||
line(Buffer, 91+(i%4)*20, 256 + (i / 4) * 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, 0xFFFFFFFF);
|
||||
line(Buffer, 91+(i%4)*20, 256 + (i / 4) * 20 + 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
if (keypressed())
|
||||
{
|
||||
keyb = (readkey() & 0xFF);
|
||||
|
||||
if (keyb == '4')
|
||||
{
|
||||
x--;
|
||||
}
|
||||
if (keyb == '8')
|
||||
{
|
||||
y--;
|
||||
}
|
||||
if (keyb == '6')
|
||||
{
|
||||
x++;
|
||||
}
|
||||
if (keyb == '2')
|
||||
{
|
||||
y++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
ppu.DisplayPalette = OldDisplayPalette;
|
||||
NOBLIT = 0;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugSprites()
|
||||
{
|
||||
#ifdef TO_MAKE
|
||||
byte keyb;
|
||||
static int SelSprite = 0;
|
||||
PPUSprite sprite;
|
||||
NOBLIT = 1;
|
||||
ppu.ControlRegister2.b |= PPU_CR2_SPRTVISIBILITY;
|
||||
|
||||
while(!key[KEY_ESC])
|
||||
{
|
||||
frame++;
|
||||
PPUVBlank();
|
||||
sprite = PPUGetSprite(SelSprite);
|
||||
|
||||
if (ppu.ControlRegister1.b & PPU_CR1_SPRTSIZE)
|
||||
{
|
||||
rect(Buffer, sprite.x-1, sprite.y-1, sprite.x+9, sprite.y+17, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rect(Buffer, sprite.x-1, sprite.y-1, sprite.x+9, sprite.y+9, 1);
|
||||
}
|
||||
|
||||
textprintf(Buffer, font, 5, 340, GetColor(3), "Sprite %d [%d:%d]", SelSprite, sprite.x, sprite.y);
|
||||
textprintf(Buffer, font, 5, 349, GetColor(3), "B0: 0x%X B1: 0x%X B2: 0x%X B3: 0x%X",sprite.y,sprite.tileid,sprite.flags.b,sprite.x);
|
||||
textprintf(Buffer, font, 5, 358, GetColor(3), "Tile Index: %d", sprite.tileid);
|
||||
textprintf(Buffer, font, 5, 367, GetColor(3), "Vertical Flip: %d", sprite.flags.s.VFlip);
|
||||
textprintf(Buffer, font, 5, 376, GetColor(3), "Horizontal Flip: %d", sprite.flags.s.HFlip);
|
||||
textprintf(Buffer, font, 5, 385, GetColor(3), "Background Priority: %d", sprite.flags.s.BgPrio);
|
||||
textprintf(Buffer, font, 5, 394, GetColor(3), "Upper Color: %d", sprite.flags.s.UpperColor);
|
||||
|
||||
blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
if (keypressed())
|
||||
{
|
||||
keyb = (readkey() & 0xFF);
|
||||
if (keyb == '+')
|
||||
SelSprite = (SelSprite<63)?SelSprite+1:0;
|
||||
if (keyb == '-')
|
||||
SelSprite = (SelSprite>0)?SelSprite-1:63;
|
||||
|
||||
if (keyb == 'h')
|
||||
{
|
||||
sprite.flags.s.HFlip = ~sprite.flags.s.HFlip;
|
||||
PPUSetSprite(SelSprite, &sprite);
|
||||
}
|
||||
if (keyb == 'b')
|
||||
{
|
||||
sprite.flags.s.BgPrio = ~sprite.flags.s.BgPrio;
|
||||
PPUSetSprite(SelSprite, &sprite);
|
||||
}
|
||||
if (keyb == 'v')
|
||||
{
|
||||
sprite.flags.s.VFlip = ~sprite.flags.s.VFlip;
|
||||
PPUSetSprite(SelSprite, &sprite);
|
||||
}
|
||||
|
||||
if (keyb == '4')
|
||||
{
|
||||
sprite.x--;
|
||||
PPUSetSprite(SelSprite, &sprite);
|
||||
}
|
||||
if (keyb == '8')
|
||||
{
|
||||
sprite.y--;
|
||||
PPUSetSprite(SelSprite, &sprite);
|
||||
}
|
||||
if (keyb == '6')
|
||||
{
|
||||
sprite.x++;
|
||||
PPUSetSprite(SelSprite, &sprite);
|
||||
}
|
||||
if (keyb == '2')
|
||||
{
|
||||
sprite.y++;
|
||||
PPUSetSprite(SelSprite, &sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
NOBLIT = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GetTilePos(addr,x,y) (addr+x+(y*32))
|
||||
|
||||
#define GetTileColor(tile,x1,y1) ( ( ppu_readMemory(((tile+y1)>>8)&0xFF, (tile+y1) & 0xFF) & (1<<(7-x1)) ) == 0 ? 0 : 1 ) | \
|
||||
( ( ppu_readMemory(((tile+y1+8)>>8) & 0xFF, (tile+y1+8) &0xFF) & (1<<(7-x1)) ) == 0 ? 0 : 1<<1 )
|
||||
|
||||
#define PPU_Rd(addr) ppu_readMemory((addr>>8)&0xFF, addr&0xFF)
|
||||
|
||||
void ppu_dumpOneNameTable(unsigned short nametable, int xd, int yd)
|
||||
{
|
||||
byte x,y, x1, y1, Color;
|
||||
unsigned short TileID;
|
||||
|
||||
for (x = 0; x < 32; x++)
|
||||
for (y = 0; y < 30; y++)
|
||||
{
|
||||
TileID = (PPU_Rd(0x2000 + nametable + x + (y * 32)) << 4) | (PPU_Reg_S);
|
||||
|
||||
for (x1 = 0; x1 < 8; x1++)
|
||||
for (y1 = 0; y1 < 8; y1++)
|
||||
{
|
||||
Color = GetTileColor(TileID, x1, y1);
|
||||
// if (ppu.DisplayAttributeTable != 0)
|
||||
// Color |= (Buffer->line[(8 * y) + 240 + y1][(8 * x) + 256 + x1] & 0x3) << 2;
|
||||
Color += (nametable>>8);
|
||||
Color = ppu_readMemory(0x3F, Color);
|
||||
|
||||
|
||||
_putpixel(Buffer, (8 * x) + xd + x1, (8 * y) + yd + y1, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_dumpOneAttributeTable(unsigned short nametable, int xd, int yd)
|
||||
{
|
||||
int x, y, x1, y1, Color, AttrByte;
|
||||
for (x = 0; x < 0x40; x++)
|
||||
{
|
||||
AttrByte = PPU_Rd(nametable + 0x23C0 + x);
|
||||
x1 = x % 8;
|
||||
y1 = x / 8;
|
||||
|
||||
Color = AttrByte & 0x3; // Pattern 1;
|
||||
// Color = PPU_Rd(0x3F00 + (Color * 4) + 1);
|
||||
rectfill(Buffer,xd+(x1*32),yd+(y1*32),xd+15+(x1*32),yd+15+(y1*32),Color);
|
||||
|
||||
textprintf_ex(Buffer, font, 4+xd+(x1*32), 4+yd+(y1*32), ~Color, Color, "%X", Color);
|
||||
|
||||
|
||||
Color = (AttrByte>>2) & 0x3; // Pattern 2;
|
||||
// Color = PPU_Rd(0x3F00 + (Color * 4) + 1);
|
||||
rectfill(Buffer,16+xd+(x1*32),yd+(y1*32),16+xd+15+(x1*32),yd+15+(y1*32),Color);
|
||||
|
||||
textprintf_ex(Buffer, font, 4+xd+(x1*32)+16, 4+yd+(y1*32), ~Color, Color, "%X", Color);
|
||||
|
||||
Color = (AttrByte>>4) & 0x3; // Pattern 3;
|
||||
// Color = PPU_Rd(0x3F00 + (Color * 4) + 1);
|
||||
rectfill(Buffer,xd+(x1*32),16+yd+(y1*32),xd+15+(x1*32),16+yd+15+(y1*32),Color);
|
||||
|
||||
textprintf_ex(Buffer, font, 4+xd+(x1*32), 4+yd+(y1*32)+16, ~Color, Color, "%X", Color);
|
||||
|
||||
Color = (AttrByte>>6) & 0x3; // Pattern 4;
|
||||
// Color = PPU_Rd(0x3F00 + (Color * 4) + 1);
|
||||
rectfill(Buffer,16+xd+(x1*32),16+yd+(y1*32),16+xd+15+(x1*32),16+yd+15+(y1*32),Color);
|
||||
|
||||
textprintf_ex(Buffer, font, 4+xd+(x1*32)+16, 4+yd+(y1*32)+16, ~Color, Color, "%X", Color);
|
||||
|
||||
rect(Buffer, xd+(x1*32), yd+(y1*32), xd+(x1*32) + 31 , yd+(y1*32) + 31, 1);
|
||||
line(Buffer, xd+(x1*32)+16, yd+(y1*32), xd+(x1*32) + 16 , yd+(y1*32) + 31, 5);
|
||||
line(Buffer, xd+(x1*32), yd+(y1*32)+16, xd+(x1*32) + 31 , yd+(y1*32) + 16, 5);
|
||||
|
||||
}
|
||||
}
|
||||
extern byte *ppu_mem_nameTables;
|
||||
extern int ppu_screenMode;
|
||||
void ppu_dumpNameTable(int xd, int yd)
|
||||
{
|
||||
// ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0x000);
|
||||
// ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0x400);
|
||||
// ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0x800);
|
||||
// ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0xC00);
|
||||
|
||||
ppu_dumpOneNameTable(0x800, xd , yd);
|
||||
ppu_dumpOneNameTable(0xC00, xd + 256, yd);
|
||||
ppu_dumpOneNameTable(0x000, xd , yd + 240);
|
||||
ppu_dumpOneNameTable(0x400, xd + 256, yd + 240);
|
||||
|
||||
// ppu_setScreenMode(ppu_screenMode);
|
||||
|
||||
}
|
||||
|
||||
void ppu_dumpAttributeTable(int xd, int yd)
|
||||
{
|
||||
ppu_dumpOneAttributeTable(0x800, xd , yd);
|
||||
ppu_dumpOneAttributeTable(0xC00, xd + 256, yd);
|
||||
ppu_dumpOneAttributeTable(0x000, xd , yd + 240);
|
||||
ppu_dumpOneAttributeTable(0x400, xd + 256, yd + 240);
|
||||
}
|
||||
|
||||
void ppu_dumpPattern(int xd, int yd)
|
||||
{
|
||||
int x1, y1, x, y, Color, i, TileID;
|
||||
/* y:346 */
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
TileID = 0x0000 + (i << 4);
|
||||
for (x = 0; x < 8; x++)
|
||||
for (y = 0; y < 8; y++)
|
||||
{
|
||||
Color = GetTileColor(TileID, x, y);
|
||||
|
||||
_putpixel(Buffer, 10 + x1 + x, 347 + y1 + y, /*ppu_readMemory(0x3F,*/ Color/*)*/);
|
||||
}
|
||||
|
||||
x1 += 8;
|
||||
if (x1 >= 128)
|
||||
{
|
||||
x1 = 0;
|
||||
y1 += 8;
|
||||
}
|
||||
}
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
TileID = 0x1000 + (i << 4);
|
||||
|
||||
for (x = 0; x < 8; x++)
|
||||
for (y = 0; y < 8; y++)
|
||||
{
|
||||
|
||||
Color = GetTileColor(TileID, x, y);
|
||||
|
||||
_putpixel(Buffer, 10 + 128 + x1 + x, 347 + y1 + y, /*ppu_readMemory(0x3F,*/ 0x10 | Color/*)*/ );
|
||||
|
||||
}
|
||||
x1 += 8;
|
||||
if (x1 >= 128)
|
||||
{
|
||||
x1 = 0;
|
||||
y1 += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_dumpPalette(int x, int y)
|
||||
{
|
||||
int i;
|
||||
|
||||
textout(Buffer, font, "Bg Palette", x , y, 5);
|
||||
textout(Buffer, font, "Sprt Palette", x + 90, y, 5);
|
||||
|
||||
rect(Buffer, x+0, y+20, x+4 * 20 + 2, y + 4 * 20 + 22, 0);
|
||||
rect(Buffer, x+90, y+20, x+90 + 4 * 20 + 2, y + 4 * 20 + 22, 0);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
rectfill(Buffer, x + 1 + (i % 4) * 20, y + 21 + (i / 4) * 20, x + 1 + (i % 4) * 20 + 20, y + 21 + (i / 4) * 20 + 20, ppu_readMemory(0x3F, i));
|
||||
rectfill(Buffer, x + 91 + (i % 4) * 20, y + 21 +(i / 4) * 20, x + 91 + (i % 4) * 20 + 20, y + 21 +(i / 4) * 20 + 20, ppu_readMemory(0x3F, i+0x10));
|
||||
}
|
||||
}
|
||||
45
src/ppu/debug/tmp.c.txt
Normal file
45
src/ppu/debug/tmp.c.txt
Normal file
@ -0,0 +1,45 @@
|
||||
if (ppu.DisplayPalette)
|
||||
{
|
||||
textout(Buffer, font, "Bg Palette", 0, 247, 5);
|
||||
textout(Buffer, font, "Sprt Palette", 90, 247, 5);
|
||||
|
||||
rect(Buffer, 0, 255, 4 * 20 + 2, 255 + 4 * 20 + 2, GetColor(0));
|
||||
rect(Buffer, 90, 255, 90 + 4 * 20 + 2, 255 + 4 * 20 + 2, GetColor(0));
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
rectfill(Buffer, 1 + (i % 4) * 20, 256 + (i / 4) * 20, 1 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, GetColor(ppu.Memory[0x3F00 + i]));
|
||||
rectfill(Buffer, 91 + (i % 4) * 20, 256 + (i / 4) * 20, 91 + (i % 4) * 20 + 20, 256 + (i / 4) * 20 + 20, GetColor(ppu.Memory[0x3F10 + i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < 240; i++)
|
||||
{
|
||||
_putpixel(Buffer, 257 + 0, i, 48);
|
||||
|
||||
_putpixel(Buffer, 257 + 1, i, ((ppu.TimedTmpPtr[y]*4))&0xFF);
|
||||
_putpixel(Buffer, 257 + 2, i, ((ppu.TimedTmpPtr[y]*4)>>8)&0xFF);
|
||||
_putpixel(Buffer, 257 + 3, i, ((ppu.TimedTmpPtr[y]*4)>>16)&0xFF);
|
||||
|
||||
_putpixel(Buffer, 257 + 4, i, ((ppu.TmpVScroll*4))&0xFF);
|
||||
_putpixel(Buffer, 257 + 5, i, ((ppu.TmpVScroll*4)>>8)&0xFF);
|
||||
_putpixel(Buffer, 257 + 6, i, ((ppu.TmpVScroll*4)>>16)&0xFF);
|
||||
|
||||
_putpixel(Buffer, 257 + 7, i, ((ppu.TimedHScroll[i]*4)) & 0xFF);
|
||||
_putpixel(Buffer, 257 + 8, i, ((ppu.TimedHScroll[i]*4)>>8) & 0xFF);
|
||||
_putpixel(Buffer, 257 + 9, i, ((ppu.TimedHScroll[i]*4)>>16)& 0xFF);
|
||||
|
||||
_putpixel(Buffer, 257 + 10, i, 48);
|
||||
}
|
||||
|
||||
if (IRQScanHit != -1)
|
||||
{
|
||||
line(Buffer, 257+12, IRQScanHit, 257+22, IRQScanHit, 10);
|
||||
line(Buffer, 257+12, IRQScanHit, 257+18, IRQScanHit-3, 10);
|
||||
line(Buffer, 257+12, IRQScanHit, 257+18, IRQScanHit+3, 10);
|
||||
}
|
||||
|
||||
NoDraw:
|
||||
textprintf(Buffer, font, 5, 340, GetColor(4), "FPS : %d IPS : %d", FPS, IPS);
|
||||
textprintf(Buffer, font, 5, 3, GetColor(4), "FPS : %d (CPU@~%2.2fMhz : %d%%)", FPS, (float) (((float) IPS) / 1000000.0), (int) ((((float) IPS) / 1770000.0) * 100.0));
|
||||
#endif
|
||||
1061
src/ppu/oldppu.c
Executable file
1061
src/ppu/oldppu.c
Executable file
File diff suppressed because it is too large
Load Diff
1311
src/ppu/ppu.24.c
Executable file
1311
src/ppu/ppu.24.c
Executable file
File diff suppressed because it is too large
Load Diff
997
src/ppu/ppu.c
Executable file
997
src/ppu/ppu.c
Executable file
@ -0,0 +1,997 @@
|
||||
/*
|
||||
* PPU emulation - The TI-NESulator Project
|
||||
* ppu.c
|
||||
*
|
||||
* Define and emulate the PPU (Picture Processing Unit) of the real NES
|
||||
*
|
||||
* Created by Manoel TRAPIER.
|
||||
* Copyright (c) 2003-2007 986Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-31 18:02:16 +0200 (jeu, 31 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/ppu.c $
|
||||
* $Revision: 58 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <allegro.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __TINES_PPU_INTERNAL__
|
||||
#include <ppu/ppu.h>
|
||||
#include <ppu/ppu.memory.h>
|
||||
#include <ppu/ppu.debug.h>
|
||||
|
||||
#include <memory/manager.h>
|
||||
|
||||
#define __TINES_PLUGINS__
|
||||
#include <plugins/manager.h>
|
||||
|
||||
#if ISPAL && !ISNTSC
|
||||
//#define VBLANK_TIME 70
|
||||
extern int VBLANK_TIME;
|
||||
#elif !ISPAL && ISNTSC
|
||||
//#define VBLANK_TIME 20
|
||||
extern int VBLANK_TIME;
|
||||
#else
|
||||
#error Cannot use ISPAL with ISNTSC together !
|
||||
#endif
|
||||
|
||||
#ifdef NO_N_KEY
|
||||
#define IF_N_KEY if (!key[KEY_N])
|
||||
#else
|
||||
#define IF_N_KEY if (key[KEY_N])
|
||||
#endif
|
||||
|
||||
extern BITMAP *Buffer;
|
||||
|
||||
volatile extern int frame;
|
||||
volatile extern unsigned long IPS, FPS;
|
||||
|
||||
extern unsigned long ColorPalette[ 9 * 63 ];
|
||||
extern short IRQScanHit;
|
||||
|
||||
BITMAP *VideoBuffer; /* The ppu will only write pixel to this, and then bliting
|
||||
this on the screen "surface" */
|
||||
|
||||
/* PPU sprite sorted by scanline */
|
||||
|
||||
/* Work as follow:
|
||||
|
||||
3322 2222 2222 1111 1111 1100 0000 0000
|
||||
1098 7654 3210 9876 5432 1098 7654 3210
|
||||
---------------------------------------
|
||||
AAAA AAAA TTTT TTTT xxxx XXXX YYYY YYYY
|
||||
---------------------------------------
|
||||
8421 8421 8421 8421 8421 8421 8421 8421
|
||||
|
||||
A = Sprite Attributes
|
||||
x = reserved
|
||||
T = Tile ID
|
||||
X = X relative position
|
||||
Y = Y absolute position
|
||||
|
||||
x = for future use
|
||||
|
||||
*/
|
||||
unsigned long PPU_SpriteByScanLine[241][9]; /* There is 240 scanline and 8 sprite per scanline */
|
||||
unsigned long PPU_NbSpriteByScanLine[241]; /* There is 240 scanline and 8 sprite per scanline */
|
||||
unsigned long PPU_NbSpriteByScanLineOverFlow[241]; /* There is 240 scanline and 8 sprite per scanline */
|
||||
|
||||
#define PPU_SCANLINESPRITE_GET_ATTRS(sprt) (((sprt)&0xFF000000) >> 24)
|
||||
#define PPU_SCANLINESPRITE_GET_TILIDX(sprt) (((sprt)&0x00FF0000) >> 16)
|
||||
#define PPU_SCANLINESPRITE_GET_RELY(sprt) (((sprt)&0x00000F00) >> 8)
|
||||
#define PPU_SCANLINESPRITE_GET_X(sprt) ((sprt)&0x000000FF)
|
||||
|
||||
#define PPU_SCANLINESPRITE_SET_ATTRS(sprt, v) sprt = (((sprt)&0x00FFFFFF) | (( (v) & 0xFF) << 24))
|
||||
#define PPU_SCANLINESPRITE_SET_TILIDX(sprt, v) sprt = (((sprt)&0xFF00FFFF) | (( (v) & 0xFF) << 16))
|
||||
#define PPU_SCANLINESPRITE_SET_RELY(sprt, v) sprt = (((sprt)&0xFFFFF0FF) | (( (v) & 0x0F) << 8))
|
||||
#define PPU_SCANLINESPRITE_SET_X(sprt, v) sprt = (((sprt)&0xFFFFFF00) | ( (v) & 0xFF ))
|
||||
|
||||
/* PPU registers */
|
||||
|
||||
/* NT: Name Table */
|
||||
byte PPU_Reg_NT;
|
||||
|
||||
/* AT: Attribute/Color Table */
|
||||
byte PPU_Reg_AT;
|
||||
|
||||
/* FV: Fine Vertical Scroll latch/counter */
|
||||
byte PPU_Reg_FV;
|
||||
|
||||
/* HV: Fine Horizontal Scroll latch/counter */
|
||||
byte PPU_Reg_FH;
|
||||
|
||||
/* VT: Vertical Tile indev latch/counter */
|
||||
byte PPU_Reg_VT;
|
||||
|
||||
/* HT: Horizontal Tile indev latch/counter */
|
||||
byte PPU_Reg_HT;
|
||||
|
||||
/* V: Vertical Name Table Selection latch/counter */
|
||||
byte PPU_Reg_V;
|
||||
|
||||
/* H: Horizontal Name Table Selection latch/counter */
|
||||
byte PPU_Reg_H;
|
||||
|
||||
/* S: Playfield pattern table selection latch */
|
||||
unsigned short PPU_Reg_S;
|
||||
|
||||
/* PAR: Picture Address Register */
|
||||
byte PPU_Reg_PAR;
|
||||
|
||||
/* AR: Tile Attribute (palette select) value latch */
|
||||
byte PPU_Reg_AR;
|
||||
|
||||
unsigned short PPU_Reg_Counter;
|
||||
|
||||
|
||||
/* PPU Memory Areas */
|
||||
byte *ppu_mem_nameTables;
|
||||
byte *ppu_mem_patternTables;
|
||||
byte *ppu_mem_paletteValues;
|
||||
|
||||
byte ppu_mem_spritesTable[0x100];
|
||||
byte ppu_mem_sptrTablePtr;
|
||||
|
||||
|
||||
/* Some other PPU "registers" */
|
||||
byte ppu_VramAccessFlipFlop;
|
||||
|
||||
byte ppu_inVBlankTime;
|
||||
byte ppu_spriteZeroHit;
|
||||
byte ppu_scanlineSpriteOverflow;
|
||||
|
||||
byte ppu_bgColor;
|
||||
|
||||
/* CR #1 variables */
|
||||
unsigned short ppu_spritePatternTable;
|
||||
byte ppu_spriteSize;
|
||||
byte ppu_addrIncrement;
|
||||
byte ppu_execNMIonVBlank;
|
||||
|
||||
/* CR #2 variables */
|
||||
byte ppu_spriteVisibility;
|
||||
byte ppu_backgroundVisibility;
|
||||
byte ppu_spriteClipping;
|
||||
byte ppu_backgroundClipping;
|
||||
byte ppu_displayType;
|
||||
|
||||
byte ppu_mirrorMode;
|
||||
byte ppu_singleScreenMode;
|
||||
byte ppu_screenMode;
|
||||
|
||||
#define PPU_MEM_PATTERNTABLES_SIZE 0x2000
|
||||
#define PPU_MEM_NAMETABLE_SIZE 0x1000
|
||||
#define PPU_MEM_PALETTEVALUES_SIZE 0x100 /* in fact its 20 but we must allocate a least one page */
|
||||
|
||||
#define PPU_SPRITE_FLAGS_VFLIP ( 1 << 7 )
|
||||
#define PPU_SPRITE_FLAGS_HFLIP ( 1 << 6 )
|
||||
#define PPU_SPRITE_FLAGS_BGPRIO ( 1 << 5 )
|
||||
#define PPU_SPRITE_FLAGS_UPPERCOLOR ( 0x03 )
|
||||
|
||||
#define PPU_FLAG_SR_VBLANK ( 1 << 7 )
|
||||
#define PPU_FLAG_SR_SPRT0 ( 1 << 6 )
|
||||
#define PPU_FLAG_SR_8SPRT ( 1 << 5 )
|
||||
#define PPU_FLAG_SR_RDWRALLOW ( 1 << 4 )
|
||||
|
||||
#define PPU_CR1_SPRTSIZE ( 1 << 5 )
|
||||
#define PPU_CR1_EXECNMI ( 1 << 7 )
|
||||
|
||||
#define PPU_CR2_BGVISIBILITY ( 1 << 3 )
|
||||
#define PPU_CR2_SPRTVISIBILITY ( 1 << 4 )
|
||||
|
||||
int ppu_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ppu_initMemory())
|
||||
return -1;
|
||||
|
||||
/* Set ppu memory parameters */
|
||||
|
||||
/* First: Allocate each memory zone */
|
||||
ppu_mem_patternTables = (byte*) malloc(PPU_MEM_PATTERNTABLES_SIZE);
|
||||
if (!ppu_mem_patternTables)
|
||||
return -1;
|
||||
|
||||
ppu_mem_nameTables = (byte*) malloc(PPU_MEM_NAMETABLE_SIZE);
|
||||
if (!ppu_mem_nameTables)
|
||||
return -1;
|
||||
|
||||
ppu_mem_paletteValues = (byte*) malloc(PPU_MEM_PALETTEVALUES_SIZE);
|
||||
if (!ppu_mem_paletteValues)
|
||||
return -1;
|
||||
|
||||
printf("ppu_mem_nameTables :%p\n"
|
||||
"ppu_mem_patternTables:%p\n"
|
||||
"ppu_mem_paletteValues:%p\n",
|
||||
ppu_mem_nameTables,
|
||||
ppu_mem_patternTables,
|
||||
ppu_mem_paletteValues);
|
||||
|
||||
/* Second: make the ppu memory manager point on the memory zones */
|
||||
ppu_setPagePtr8k(0x00, ppu_mem_patternTables);
|
||||
ppu_setPagePtr4k(0x20, ppu_mem_nameTables);
|
||||
ppu_setPagePtr (0x3F, ppu_mem_paletteValues);
|
||||
|
||||
for ( i = 0x00; i < 0x0F; i++ )
|
||||
ppu_setPageGhost(0x30 + i, true, 0x20 + i);
|
||||
|
||||
/* Third: set registers to defaults */
|
||||
|
||||
|
||||
/* Now test the memory ! */
|
||||
|
||||
/* Fille PPU memory with garbage */
|
||||
for (i = 0x0000; i < 0x2000 ; i++)
|
||||
ppu_mem_patternTables[i] = rand()%0xFF;
|
||||
for (i = 0x0000; i < 0x1000 ; i++)
|
||||
ppu_mem_nameTables[i] = rand()%0xFF;
|
||||
for (i = 0x0000; i < 0x001F ; i++)
|
||||
ppu_mem_paletteValues[i] = rand()%0xFF;
|
||||
|
||||
|
||||
/* Dump PPU memory state */
|
||||
//ppu_memoryDumpState(stdout);
|
||||
|
||||
/* Set some other variables */
|
||||
ppu_VramAccessFlipFlop = 0;
|
||||
|
||||
ppu_addrIncrement = 1;
|
||||
ppu_spritePatternTable = 0;
|
||||
ppu_spriteSize = 8;
|
||||
ppu_execNMIonVBlank = 0;
|
||||
|
||||
ppu_spriteVisibility = 0;
|
||||
ppu_backgroundVisibility = 0;
|
||||
ppu_spriteClipping = 0;
|
||||
ppu_backgroundClipping = 0;
|
||||
ppu_displayType = 0;
|
||||
|
||||
ppu_inVBlankTime = 0;
|
||||
ppu_bgColor = 0;
|
||||
|
||||
/* Set PPU registers on CPU side */
|
||||
set_page_rd_hook(0x20, ppu_readReg);
|
||||
set_page_wr_hook(0x20, ppu_writeReg);
|
||||
|
||||
set_page_readable(0x20, true);
|
||||
set_page_writeable(0x20, true);
|
||||
|
||||
|
||||
/* Set PPU Ghost Registers */
|
||||
for(i = 0x21; i < 0x40; i++)
|
||||
set_page_ghost(i, true, 0x20);
|
||||
|
||||
// plugin_install_keypressHandler('i', ppu_debugSprites);
|
||||
// plugin_install_keypressHandler('I', ppu_debugSprites);
|
||||
|
||||
// plugin_install_keypressHandler('u', ppu_debugColor);
|
||||
// plugin_install_keypressHandler('U', ppu_debugColor);
|
||||
|
||||
/* allocate the PPU Video memory */
|
||||
VideoBuffer = create_bitmap(256, 240);
|
||||
|
||||
if (VideoBuffer == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ppu_updateSpriteScanlineTable()
|
||||
{
|
||||
int i, line, j, k;
|
||||
volatile int sprite_x, sprite_y, sprite_idx, sprite_attr;
|
||||
|
||||
int curline;
|
||||
|
||||
for (line = 0; line < 241; line ++)
|
||||
{
|
||||
PPU_NbSpriteByScanLine[line] = 0;
|
||||
PPU_NbSpriteByScanLineOverFlow[line] = 0;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
PPU_SpriteByScanLine[line][i] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
for ( i = 0; i < 64; i ++)
|
||||
{
|
||||
/* Fill sprite_zzz variables */
|
||||
sprite_y = ppu_mem_spritesTable[(i*4) + 0];
|
||||
sprite_idx = ppu_mem_spritesTable[(i*4) + 1];
|
||||
sprite_attr = ppu_mem_spritesTable[(i*4) + 2] | ((i==0)?0x04:0); /* Add a flag for the sprite #0 */
|
||||
sprite_x = ppu_mem_spritesTable[(i*4) + 3];
|
||||
|
||||
/* For each line covered by the sprite */
|
||||
for (line = 0; line < ppu_spriteSize; line ++)
|
||||
{
|
||||
curline = line + sprite_y;
|
||||
|
||||
if ((curline < 0) || (curline > 240))
|
||||
continue; /* Don't go beyond, this sprite go beyond the borders */
|
||||
|
||||
if (PPU_NbSpriteByScanLine[curline] < 7)
|
||||
PPU_NbSpriteByScanLine[curline] ++;
|
||||
else
|
||||
{
|
||||
PPU_NbSpriteByScanLineOverFlow[curline] = 1;
|
||||
//printf("sprite of: %d - %d\n", curline, PPU_NbSpriteByScanLine[curline]);
|
||||
continue; /* We have 8 sprite in this line, don't continue */
|
||||
}
|
||||
|
||||
if (((sprite_x+8) < 0) && ((sprite_x-8) > 256))
|
||||
continue; /* this sprite isn't either displayable */
|
||||
/* Now test if this sprite can be put in the sprite list */
|
||||
for (j = 0; j <= PPU_NbSpriteByScanLine[curline]; j++)
|
||||
{
|
||||
/* sprite are ordered by their y value, so, the first time that
|
||||
we have lower y value is where we need to put the sprite */
|
||||
if (sprite_x < PPU_SCANLINESPRITE_GET_X(PPU_SpriteByScanLine[curline][j]))
|
||||
{
|
||||
/* move the j eme item and next to the right in the list, trashing
|
||||
if needed the rightest item. */
|
||||
for (k = 7; k >= j; k--)
|
||||
PPU_SpriteByScanLine[curline][k] = PPU_SpriteByScanLine[curline][k-1];
|
||||
|
||||
PPU_SpriteByScanLine[curline][j] = 0;
|
||||
|
||||
PPU_SCANLINESPRITE_SET_ATTRS (PPU_SpriteByScanLine[curline][j], sprite_attr);
|
||||
//printf("new sprite [%02X:%02X:%02X:%02X] at sl:%d : 0x%08X ",
|
||||
//sprite_attr, sprite_idx, curline - sprite_x, sprite_y,
|
||||
//curline, PPU_SpriteByScanLine[curline][j]);
|
||||
|
||||
PPU_SCANLINESPRITE_SET_TILIDX(PPU_SpriteByScanLine[curline][j], sprite_idx);
|
||||
//printf("- 0x%08X ", PPU_SpriteByScanLine[curline][j]);
|
||||
|
||||
PPU_SCANLINESPRITE_SET_RELY (PPU_SpriteByScanLine[curline][j], curline - sprite_y);
|
||||
//printf("- 0x%08X ", PPU_SpriteByScanLine[curline][j]);
|
||||
|
||||
PPU_SCANLINESPRITE_SET_X (PPU_SpriteByScanLine[curline][j], sprite_x);
|
||||
//printf("- 0x%08X\n", PPU_SpriteByScanLine[curline][j]);
|
||||
|
||||
break; /* Stop the for, we don't need to go further in the line list */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_setMirroring(byte direction)
|
||||
{
|
||||
if (ppu_screenMode != PPU_SCMODE_NORMAL)
|
||||
return;
|
||||
|
||||
if (ppu_mirrorMode == direction)
|
||||
return; /* Same value, no need to change! */
|
||||
|
||||
switch(direction)
|
||||
{
|
||||
default:
|
||||
direction = PPU_MIRROR_HORIZTAL;
|
||||
ppu_mirrorMode = direction;
|
||||
|
||||
case PPU_MIRROR_HORIZTAL: /* Horizontal */
|
||||
//printf("Set mirror to Hor\n");
|
||||
ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0x400);
|
||||
ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0x400);
|
||||
break;
|
||||
case PPU_MIRROR_VERTICAL: /* Vertical */
|
||||
//printf("Set mirror to Ver\n");
|
||||
ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0x400);
|
||||
ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0x400);
|
||||
break;
|
||||
}
|
||||
ppu_mirrorMode = direction;
|
||||
}
|
||||
|
||||
void ppu_setSingleScreen(byte screen)
|
||||
{
|
||||
if (ppu_screenMode != PPU_SCMODE_SINGLE)
|
||||
return;
|
||||
if (ppu_singleScreenMode == screen)
|
||||
return; /* Same value, no need to change! */
|
||||
|
||||
switch(screen)
|
||||
{
|
||||
default:
|
||||
screen = PPU_SCREEN_000;
|
||||
ppu_singleScreenMode = screen;
|
||||
|
||||
case PPU_SCREEN_000: /* 0x2000 */
|
||||
//printf("Set screen to 0x000\n");
|
||||
ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0x000);
|
||||
break;
|
||||
|
||||
case PPU_SCREEN_400: /* 0x2400 */
|
||||
//printf("Set screen to 0x400\n");
|
||||
ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0x400);
|
||||
ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0x400);
|
||||
ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0x400);
|
||||
ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0x400);
|
||||
break;
|
||||
|
||||
case PPU_SCREEN_800: /* 0x2800 */
|
||||
//printf("Set screen to 0x800\n");
|
||||
ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0x800);
|
||||
ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0x800);
|
||||
ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0x800);
|
||||
ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0x800);
|
||||
break;
|
||||
|
||||
case PPU_SCREEN_C00: /* 0x2C00 */
|
||||
//printf("Set screen to 0xC00\n");
|
||||
ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0xC00);
|
||||
ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0xC00);
|
||||
ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0xC00);
|
||||
ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0xC00);
|
||||
break;
|
||||
}
|
||||
ppu_singleScreenMode = screen;
|
||||
}
|
||||
|
||||
/* Let set display to
|
||||
Single screen (1 NT with mirroring)
|
||||
Normal screen (2 NT with mirroring)
|
||||
Four screen (4 NT without mirroring) */
|
||||
void ppu_setScreenMode(byte mode)
|
||||
{
|
||||
if (ppu_screenMode == mode)
|
||||
return; /* Same value, no need to change! */
|
||||
|
||||
ppu_screenMode = mode;
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case PPU_SCMODE_SINGLE: /* Single screen (1 NT with mirroring) */
|
||||
//printf("Set Single Screen\n");
|
||||
ppu_setSingleScreen(~ppu_singleScreenMode);
|
||||
break;
|
||||
|
||||
default:
|
||||
mode = PPU_SCMODE_NORMAL;
|
||||
ppu_screenMode = mode;
|
||||
|
||||
case PPU_SCMODE_NORMAL: /* Normal screen (2 NT with mirroring) */
|
||||
//printf("Set Normal Screen\n");
|
||||
ppu_setMirroring(~ppu_mirrorMode);
|
||||
break;
|
||||
|
||||
case PPU_SCMODE_FOURSC: /* Four screen (4 NT withou mirroring) */
|
||||
//printf("Set Four Screen\n");
|
||||
ppu_setPagePtr1k(0x20, ppu_mem_nameTables + 0x000);
|
||||
ppu_setPagePtr1k(0x24, ppu_mem_nameTables + 0x400);
|
||||
ppu_setPagePtr1k(0x28, ppu_mem_nameTables + 0x800);
|
||||
ppu_setPagePtr1k(0x2C, ppu_mem_nameTables + 0xC00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_setSprite(unsigned short i, PPU_Sprite *sprt)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* update whole counters */
|
||||
void ppu_updateCounters()
|
||||
{
|
||||
/*
|
||||
+---------------+-----------------------------------------------+
|
||||
| |+===++=++=++=====++=====++===++=++========++==+|
|
||||
|PPU registers || FV||V||H|| VT|| HT|| FH||S|| PAR||AR||
|
||||
|PPU counters |+---++-++-++-----++-----++===++=++========++==+|
|
||||
| |+===++=++=++=====++=====+ |
|
||||
+---------------+-----------------------------------------------+
|
||||
|2007 access | DC B A 98765 43210 |
|
||||
+===============+===============================================+
|
||||
|
||||
8421 8421 8421 8421
|
||||
-------------------
|
||||
1111 1100 0000 0000
|
||||
5432 1098 7654 3210
|
||||
_AAA BCDD DDDE EEEE
|
||||
|
||||
*/
|
||||
PPU_Reg_Counter = (PPU_Reg_FV & 0x07) << 12;
|
||||
PPU_Reg_Counter |= PPU_Reg_V << 11;
|
||||
PPU_Reg_Counter |= PPU_Reg_H << 10;
|
||||
PPU_Reg_Counter |= PPU_Reg_VT << 5;
|
||||
PPU_Reg_Counter |= PPU_Reg_HT;
|
||||
|
||||
IF_N_KEY printf("Counter update to %04X\n",PPU_Reg_Counter);
|
||||
}
|
||||
|
||||
int ppu_hblank(int scanline)
|
||||
{
|
||||
int i, j;
|
||||
byte pixelColor = 0x42;
|
||||
byte Color = 0x42;
|
||||
unsigned short addr;
|
||||
byte value;
|
||||
unsigned short tmp_HHT = 0;
|
||||
unsigned short tmp_VVTFV = 0;
|
||||
|
||||
/* If no plan activated, we have nothing to do ! */
|
||||
|
||||
if (scanline == 0)
|
||||
{
|
||||
ppu_bgColor = ppu_readMemory(0x3F,00);
|
||||
clear_to_color(VideoBuffer, ppu_bgColor);
|
||||
|
||||
if ((ppu_spriteVisibility != 0) || (ppu_backgroundVisibility != 0))
|
||||
ppu_updateCounters();
|
||||
}
|
||||
|
||||
if (scanline < 240)
|
||||
{
|
||||
|
||||
/* For each PPU pixel of this scanline */
|
||||
for (i = 0; i < 256; i ++)
|
||||
{
|
||||
|
||||
/* determine which from sprite bg, bg and sprite fg is in the front */
|
||||
pixelColor = ppu_readMemory(0x3F,00);
|
||||
|
||||
/* is there sprite(s) on this line ? */
|
||||
|
||||
/* */
|
||||
/* Didn't display sprite for now, juste the BG */
|
||||
|
||||
/* Read NameTable */
|
||||
if (ppu_backgroundVisibility == 1)
|
||||
{
|
||||
/*
|
||||
xxxx AABB BxxC CCxx
|
||||
xxxx AA11 11BB BCCC
|
||||
*/
|
||||
/*
|
||||
s:32 i:235 cnt:089D addr:0BCF cba:0 addr:0000
|
||||
|
||||
0000 BBBB CCCC FFFF
|
||||
0000 1100 1101 1111
|
||||
|
||||
AABB B C CC
|
||||
|
||||
BA98 7654 3210
|
||||
|
||||
xxxx 1111 1100 1111
|
||||
FFFF CCCC FFFF
|
||||
|
||||
*/
|
||||
|
||||
addr = (PPU_Reg_Counter & 0x0C00);
|
||||
addr = addr | 0x03C0;
|
||||
addr |= (PPU_Reg_Counter >> 4 ) & 0x0038;
|
||||
addr |= (PPU_Reg_Counter >> 2 ) & 0x0007;
|
||||
|
||||
PPU_Reg_AR = ppu_readMemory(0x20 | ((addr>>8) & 0x0F), addr& 0xFF);
|
||||
|
||||
|
||||
PPU_Reg_AR = PPU_Reg_AR >> (((PPU_Reg_Counter >> 4 ) & 0x04)|((PPU_Reg_Counter ) & 0x02));
|
||||
PPU_Reg_AR = (PPU_Reg_AR<<2) & 0x0C;
|
||||
|
||||
PPU_Reg_PAR = ppu_readMemory(0x20 | ((PPU_Reg_Counter>>8) & 0x0F), PPU_Reg_Counter& 0xFF);
|
||||
/* C BA98 7654 3210 */
|
||||
/* 1 8421 8421 8421 */
|
||||
|
||||
addr = PPU_Reg_S;
|
||||
addr |= ((PPU_Reg_PAR & 0xFF) << 4);
|
||||
addr |= ((PPU_Reg_Counter >> 12) & 0x07);
|
||||
value = ppu_readMemory((addr >> 8) , addr );
|
||||
Color = (value & (1 << (7-(i + PPU_Reg_FH) % 8)))?0x01:0;
|
||||
|
||||
value = ppu_readMemory((addr >> 8) , addr | 0x08 );
|
||||
Color |= (value & (1 << (7-(i + PPU_Reg_FH) % 8)))?0x02:0;
|
||||
|
||||
if (Color > 0x00)
|
||||
{
|
||||
|
||||
Color |= PPU_Reg_AR;
|
||||
Color &= 0x0F;
|
||||
|
||||
pixelColor = ppu_readMemory(0x3F, Color);
|
||||
|
||||
}
|
||||
|
||||
if (((i + PPU_Reg_FH)%8) == 7)
|
||||
{
|
||||
tmp_HHT = ((PPU_Reg_Counter >> 5) & 0x0020) |
|
||||
(PPU_Reg_Counter & 0x001F);
|
||||
tmp_HHT = (tmp_HHT + 1) & 0x003F;
|
||||
|
||||
/* Reassemble with HT & H */
|
||||
PPU_Reg_Counter = (PPU_Reg_Counter & 0xFBE0) |
|
||||
((tmp_HHT & 0x0020) << 5) |
|
||||
(tmp_HHT & 0x001F);
|
||||
}
|
||||
|
||||
}
|
||||
/* draw the pixel */
|
||||
_putpixel(VideoBuffer, i, scanline, pixelColor);
|
||||
}
|
||||
/* Increment only V & VT & FV*/
|
||||
|
||||
/*
|
||||
|
||||
8421 8421 8421 8421
|
||||
-------------------
|
||||
1111 1100 0000 0000
|
||||
5432 1098 7654 3210
|
||||
_AAA BCDD DDDE EEEE
|
||||
|
||||
xxx x xx xxx : vvtfv = 7BE0
|
||||
x x xxxx : hht
|
||||
|
||||
B DDDD DAAA : vvtfv
|
||||
CE EEEE : hht
|
||||
|
||||
A = FV
|
||||
B = V
|
||||
C = H
|
||||
D = VT
|
||||
E = HT
|
||||
|
||||
|
||||
*/
|
||||
if (ppu_backgroundVisibility == 1)
|
||||
{
|
||||
|
||||
tmp_VVTFV = ((PPU_Reg_Counter >> 3 ) & 0x0100) | /* V */
|
||||
((PPU_Reg_Counter >> 2 ) & 0x00F8) | /* VT */
|
||||
((PPU_Reg_Counter >> 12) & 0x0007); /* FV */
|
||||
//printf("counter:%04X vvtfv:%04X ", PPU_Reg_Counter, tmp_VVTFV);
|
||||
|
||||
tmp_VVTFV++;
|
||||
//printf("__ vvtfv:0x%04X == 0x%04X ? ", tmp_VVTFV, 30<<3);
|
||||
if ((tmp_VVTFV&0x0F8) == 0xF0)
|
||||
{
|
||||
tmp_VVTFV &= ~0x0F8;
|
||||
tmp_VVTFV ^= 0x100;
|
||||
//printf("YES _");
|
||||
}
|
||||
|
||||
//printf("vvtfv:%04X ", tmp_VVTFV);
|
||||
PPU_Reg_Counter = ( PPU_Reg_Counter & 0x041F) |
|
||||
((tmp_VVTFV & 0x0100 ) << 3 ) | /* V */
|
||||
((tmp_VVTFV & 0x00F8 ) << 2 ) | /* VT */
|
||||
((tmp_VVTFV & 0x0007 ) << 12); /* FV */
|
||||
|
||||
//printf("counter:%04X ", PPU_Reg_Counter);
|
||||
/* Update H & HT */
|
||||
PPU_Reg_Counter = (PPU_Reg_Counter & ~0x041F) |
|
||||
(PPU_Reg_H << 10) |
|
||||
PPU_Reg_HT;
|
||||
}
|
||||
|
||||
if (PPU_NbSpriteByScanLine[scanline] != 0)
|
||||
{
|
||||
for (j = 0; j < PPU_NbSpriteByScanLine[scanline]; j++)
|
||||
{
|
||||
static byte i = 0;
|
||||
pixelColor = (i = (i+1)%4) | ((PPU_SCANLINESPRITE_GET_ATTRS(PPU_SpriteByScanLine[scanline][j]) << 2) & 0x0C);
|
||||
|
||||
pixelColor = ppu_readMemory(0x3F, 0x10 + pixelColor);
|
||||
line(VideoBuffer,
|
||||
PPU_SCANLINESPRITE_GET_X(PPU_SpriteByScanLine[scanline][j]),
|
||||
scanline,
|
||||
PPU_SCANLINESPRITE_GET_X(PPU_SpriteByScanLine[scanline][j]) + 8,
|
||||
scanline, pixelColor
|
||||
);
|
||||
|
||||
if (PPU_SCANLINESPRITE_GET_ATTRS(PPU_SpriteByScanLine[scanline][j]) & 0x04)
|
||||
{
|
||||
//printf("Hit!\n");
|
||||
ppu_spriteZeroHit = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
ppu_scanlineSpriteOverflow = 0;
|
||||
if (PPU_NbSpriteByScanLineOverFlow[scanline] == 1)
|
||||
ppu_scanlineSpriteOverflow = 1;
|
||||
|
||||
}
|
||||
|
||||
/* if (scanline == 100)
|
||||
ppu_spriteZeroHit = 1;*/
|
||||
|
||||
if (scanline == 243)
|
||||
{
|
||||
ppu_inVBlankTime = 1;
|
||||
IF_N_KEY printf("============= enter vblank =================\n");
|
||||
return ppu_execNMIonVBlank;
|
||||
}
|
||||
|
||||
if (key[KEY_B])
|
||||
{
|
||||
blit(VideoBuffer, Buffer, 0, 0, 0, 0, 256, 240);
|
||||
blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
}
|
||||
|
||||
|
||||
//if (scanline >= (241 + VBLANK_TIME))
|
||||
if (scanline >= 262)
|
||||
{
|
||||
//textprintf(Buffer, font, 5, 340, 4, "(SL:%d) FPS : %d IPS : %d", scanline, FPS, IPS);
|
||||
textprintf(screen, font, 260, 3, 4, "FPS : %d (CPU@~%2.2fMhz : %d%%)", FPS, (float) (((float) IPS) / 1000000.0), (int) ((((float) IPS) / 1770000.0) * 100.0));
|
||||
//printf("(SL:%d) FPS : %d IPS : %d\n", scanline, FPS, IPS);
|
||||
|
||||
//ppu_dumpPalette(0, 241);
|
||||
//ppu_dumpPattern(280, 150);
|
||||
//ppu_dumpNameTable(256,0);
|
||||
//ppu_dumpAttributeTable(257, 0);
|
||||
|
||||
//blit(VideoBuffer, Buffer, 0, 0, 0, 0, 256, 240);
|
||||
blit(VideoBuffer, screen, 0, 0, 0, 0, 256, 240);
|
||||
//blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
|
||||
IF_N_KEY printf("_____________ leave vblank _________________\n");
|
||||
ppu_inVBlankTime = 0;
|
||||
ppu_spriteZeroHit = 0;
|
||||
//ppu_updateCounters();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte PPU_RegValues[8];
|
||||
|
||||
byte ppu_readReg(byte id)
|
||||
{
|
||||
id &= 0x07;
|
||||
static byte garbage;
|
||||
static byte lastValue;
|
||||
switch(id)
|
||||
{
|
||||
default:
|
||||
garbage = PPU_RegValues[id];
|
||||
printf("%s: try to read 0x20%02X\n", __func__, id);
|
||||
break;
|
||||
case 0x02: /* PPU Status Register */
|
||||
|
||||
/* Reset VRam 2005/2006 flipflop */
|
||||
ppu_VramAccessFlipFlop = 0;
|
||||
garbage = 0;
|
||||
|
||||
garbage |= (ppu_inVBlankTime!=0) ?PPU_FLAG_SR_VBLANK:0;
|
||||
garbage |= (ppu_spriteZeroHit!=0) ?PPU_FLAG_SR_SPRT0:0;
|
||||
garbage |= (ppu_scanlineSpriteOverflow!=0)?PPU_FLAG_SR_8SPRT:0;
|
||||
/*garbage ^= PPU_FLAG_SR_RDWRALLOW;*/
|
||||
|
||||
IF_N_KEY printf("%s() = %02X\n", __func__, garbage);
|
||||
|
||||
ppu_inVBlankTime = 0;
|
||||
break;
|
||||
|
||||
case 0x04: /* SPR-RAM I/O */
|
||||
garbage = ppu_mem_spritesTable[ppu_mem_sptrTablePtr];
|
||||
break;
|
||||
|
||||
case 0x07: /* VRAM I/O */
|
||||
if (PPU_Reg_Counter < 0x3F00)
|
||||
{
|
||||
garbage = lastValue;
|
||||
lastValue = ppu_readMemory((PPU_Reg_Counter>>8) & 0x3F,
|
||||
PPU_Reg_Counter & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastValue = ppu_readMemory( 0x2F,
|
||||
PPU_Reg_Counter & 0xFF);
|
||||
garbage = ppu_readMemory( 0x3F,
|
||||
PPU_Reg_Counter & 0xFF);
|
||||
}
|
||||
|
||||
PPU_Reg_Counter += ppu_addrIncrement;
|
||||
|
||||
break;
|
||||
}
|
||||
//printf("ppuread %02X return: %02X\n", id, garbage);
|
||||
return garbage;
|
||||
}
|
||||
|
||||
|
||||
void ppu_writeReg(byte id, byte val)
|
||||
{
|
||||
id &= 0x07;
|
||||
//printf("ppuwrte %02X val: %02X\n", id, val);
|
||||
PPU_RegValues[id] = val;
|
||||
switch(id)
|
||||
{
|
||||
default:
|
||||
printf("%s: try to write 0x%02X @ 0x20%02X\n", __func__, val, id);
|
||||
break;
|
||||
|
||||
case 0x00: /* PPU Control Register #1 */
|
||||
|
||||
/*
|
||||
+===============+===============================================+
|
||||
|2000 | 1 0 4 |
|
||||
+---------------+-----------------------------------------------+
|
||||
| |+===++=++=++=====++=====++===++=++========++==+|
|
||||
|PPU registers || FV||V||H|| VT|| HT|| FH||S|| PAR||AR||
|
||||
|PPU counters |+---++-++-++-----++-----++===++=++========++==+|
|
||||
| |+===++=++=++=====++=====+ |
|
||||
+---------------+-----------------------------------------------+
|
||||
*/
|
||||
IF_N_KEY
|
||||
printf("%s(%02X, %02X); /* 2000: "
|
||||
"NMI:%c SPRTSIZE:%02d BGTA:%04X[0x%04X] SPTA:%04X INC:%02d NTA:%04X */\n"
|
||||
, __func__, id, val,
|
||||
(val & 0x80)?'E':'D',
|
||||
(val & 0x20)?16:8,
|
||||
(val & 0x10)?0x1000:0x0000, PPU_Reg_S,
|
||||
(val & 0x08)?0x1000:0x0000,
|
||||
(val & 0x04)?32:1,
|
||||
(val & 0x03)<<10|0x2000
|
||||
);
|
||||
|
||||
/* Set PPU internal registers */
|
||||
PPU_Reg_V = (val & 0x02)?1:0;
|
||||
PPU_Reg_H = (val & 0x01)?1:0;
|
||||
PPU_Reg_S = (val & 0x10)?0x1000:0x0000;
|
||||
|
||||
/* Set Other parameters */
|
||||
ppu_addrIncrement = (val & 0x04)?0x20:0x01;
|
||||
ppu_spritePatternTable = (val & 0x08)?0x1000:0;
|
||||
ppu_spriteSize = (val & 0x20)?16:8;
|
||||
ppu_execNMIonVBlank = (val & 0x80)?1:0;
|
||||
break;
|
||||
|
||||
case 0x01: /* PPU Control Register #2 */
|
||||
|
||||
ppu_spriteVisibility = (val & 0x10)?1:0;
|
||||
ppu_backgroundVisibility = (val & 0x08)?1:0;
|
||||
ppu_spriteClipping = (val & 0x04)?1:0;
|
||||
ppu_backgroundClipping = (val & 0x02)?1:0;
|
||||
ppu_displayType = (val & 0x01)?1:0;
|
||||
|
||||
IF_N_KEY
|
||||
printf("%s(%02X, %02X); /* 2001 : "
|
||||
"SprtV:%c BckgV:%c SprtC:%c BckgC:%c DispT:%c"
|
||||
" */\n", __func__, id, val,
|
||||
ppu_spriteVisibility?'y':'n',
|
||||
ppu_backgroundVisibility?'y':'n',
|
||||
ppu_spriteClipping?'y':'n',
|
||||
ppu_backgroundClipping?'y':'n',
|
||||
ppu_displayType?'m':'c'
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 0x03: /* SPR-RAM Address Register */
|
||||
ppu_mem_sptrTablePtr = val;
|
||||
break;
|
||||
|
||||
case 0x04: /* SPR-RAM I/O */
|
||||
ppu_mem_spritesTable[ppu_mem_sptrTablePtr++] = val;
|
||||
|
||||
ppu_updateSpriteScanlineTable();
|
||||
|
||||
break;
|
||||
|
||||
case 0x05: /* 2005 VRAM Register */
|
||||
/*
|
||||
+===============+===============================================+
|
||||
|2005/1 | 76543 210 |
|
||||
|2005/2 | 210 76543 |
|
||||
+---------------+-----------------------------------------------+
|
||||
| |+===++=++=++=====++=====++===++=++========++==+|
|
||||
|PPU registers || FV||V||H|| VT|| HT|| FH||S|| PAR||AR||
|
||||
|PPU counters |+---++-++-++-----++-----++===++=++========++==+|
|
||||
| |+===++=++=++=====++=====+ |
|
||||
+---------------+-----------------------------------------------+
|
||||
*/
|
||||
if (ppu_VramAccessFlipFlop == 0)
|
||||
{
|
||||
ppu_VramAccessFlipFlop = ~0;
|
||||
|
||||
PPU_Reg_FH = val & 0x07;
|
||||
PPU_Reg_HT = (val & 0xF8) >> 3;
|
||||
IF_N_KEY
|
||||
printf("2005/1[%04X]: fv:%01X v:%01X h:%01X vt:%01X ht:%01X fh:%01X\n",val,PPU_Reg_FV,PPU_Reg_V,PPU_Reg_H,PPU_Reg_VT,PPU_Reg_HT,PPU_Reg_FH);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu_VramAccessFlipFlop = 0;
|
||||
|
||||
PPU_Reg_FV = val & 0x07;
|
||||
PPU_Reg_VT = (val & 0xF8) >> 3;
|
||||
IF_N_KEY
|
||||
printf("2005/2[%04X]: fv:%01X v:%01X h:%01X vt:%01X ht:%01X fh:%01X\n",val,PPU_Reg_FV,PPU_Reg_V,PPU_Reg_H,PPU_Reg_VT,PPU_Reg_HT,PPU_Reg_FH);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x06: /* 2006 VRAM Register */
|
||||
/*
|
||||
+===============+===============================================+
|
||||
|2006/1 | -54 3 2 10 |
|
||||
|2006/2 | 765 43210 |
|
||||
+---------------+-----------------------------------------------+
|
||||
| |+===++=++=++=====++=====++===++=++========++==+|
|
||||
|PPU registers || FV||V||H|| VT|| HT|| FH||S|| PAR||AR||
|
||||
|PPU counters |+---++-++-++-----++-----++===++=++========++==+|
|
||||
| |+===++=++=++=====++=====+ |
|
||||
+---------------+-----------------------------------------------+
|
||||
*/
|
||||
if (ppu_VramAccessFlipFlop == 0)
|
||||
{
|
||||
ppu_VramAccessFlipFlop = ~0;
|
||||
|
||||
PPU_Reg_FV = (val >> 4) & 0x03;
|
||||
PPU_Reg_V = (val >> 3) & 0x01;
|
||||
PPU_Reg_H = (val >> 2) & 0x01;
|
||||
PPU_Reg_VT = (PPU_Reg_VT & 0x07) | ((val & 0x03) << 3);
|
||||
IF_N_KEY
|
||||
printf("2006/1[%04X]: fv:%01X v:%01X h:%01X vt:%01X ht:%01X fh:%01X\n",val,PPU_Reg_FV,PPU_Reg_V,PPU_Reg_H,PPU_Reg_VT,PPU_Reg_HT,PPU_Reg_FH);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu_VramAccessFlipFlop = 0;
|
||||
PPU_Reg_VT = (PPU_Reg_VT & 0x18) | ((val >> 5) & 0x07);
|
||||
PPU_Reg_HT = val & 0x1F;
|
||||
|
||||
IF_N_KEY
|
||||
printf("2006/2[%04X]: fv:%01X v:%01X h:%01X vt:%01X ht:%01X fh:%01X\n",val,PPU_Reg_FV,PPU_Reg_V,PPU_Reg_H,PPU_Reg_VT,PPU_Reg_HT,PPU_Reg_FH);
|
||||
|
||||
ppu_updateCounters();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x07: /* VRAM I/O */
|
||||
/*
|
||||
+---------------+-----------------------------------------------+
|
||||
| |+===++=++=++=====++=====++===++=++========++==+|
|
||||
|PPU registers || FV||V||H|| VT|| HT|| FH||S|| PAR||AR||
|
||||
|PPU counters |+---++-++-++-----++-----++===++=++========++==+|
|
||||
| |+===++=++=++=====++=====+ |
|
||||
+---------------+-----------------------------------------------+
|
||||
|2007 access | DC B A 98765 43210 |
|
||||
+===============+===============================================+
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//if ( (PPU_Reg_Counter&0xFF00) == 0x3F00)
|
||||
//{
|
||||
// printf("fv:%01X v:%01X h:%01X vt:%01X ht:%01X fh:%01X\n",PPU_Reg_FV,PPU_Reg_V,PPU_Reg_H,PPU_Reg_VT,PPU_Reg_HT,PPU_Reg_FH);
|
||||
// printf("will write ppu: counter:%04X pa:%02X%02X v:%02X\n",
|
||||
// PPU_Reg_Counter, (PPU_Reg_Counter>>8) & 0x3F, PPU_Reg_Counter & 0xFF, val);
|
||||
// }
|
||||
|
||||
ppu_writeMemory((PPU_Reg_Counter>>8) & 0x3F, PPU_Reg_Counter & 0xFF, val);
|
||||
|
||||
IF_N_KEY
|
||||
{
|
||||
ppu_dumpPalette(0, 241);
|
||||
ppu_dumpPattern(280, 150);
|
||||
ppu_dumpNameTable(256,0);
|
||||
blit(Buffer, screen, 0, 0, 0, 0, 512 + 256, 480);
|
||||
}
|
||||
|
||||
PPU_Reg_Counter += ppu_addrIncrement;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_fillSprRamDMA(byte value)
|
||||
{
|
||||
short i;
|
||||
byte *ptr = get_page_ptr(value);
|
||||
for (i = 0; i < 0x100; i++)
|
||||
{
|
||||
ppu_mem_spritesTable[(ppu_mem_sptrTablePtr + i)&0xFF] = *(ptr+i);
|
||||
}
|
||||
//memcpy(ppu_mem_spritesTable, ptr, 0xFF);
|
||||
ppu_updateSpriteScanlineTable();
|
||||
}
|
||||
181
src/ppu/ppu.memory.c
Normal file
181
src/ppu/ppu.memory.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* PPU Memory manager - The TI-NESulator Project
|
||||
* ppu.memory.c - Inspired from the memory manager of the Quick6502 Project.
|
||||
*
|
||||
* Created by Manoël Trapier on 12/04/07.
|
||||
* Copyright 2003-2007 986 Corp. All rights reserved.
|
||||
*
|
||||
* $LastChangedDate: 2007-05-24 15:11:55 +0200 (jeu, 24 mai 2007) $
|
||||
* $Author: mtrapier $
|
||||
* $HeadURL: file:///media/HD6G/SVNROOT/trunk/TI-NESulator/src/ppu/ppu.memory.c $
|
||||
* $Revision: 53 $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PPU_MEMORY_H
|
||||
#define PPU_MEMORY_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __TINES_PPU_INTERNAL__
|
||||
|
||||
#include <ppu/ppu.h>
|
||||
#include <ppu/ppu.memory.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/* Simple definition only for readability */
|
||||
#define KBYTE * (1024)
|
||||
|
||||
/* Internal representation of the PPU memory */
|
||||
byte *ppu_memoryPages[0x40];
|
||||
|
||||
byte ppu_memoryGhostLink[0x40];
|
||||
|
||||
/* Internal PPU Sprite Ram */
|
||||
byte ppu_SpriteRam[0x100];
|
||||
|
||||
/*
|
||||
* Memory management functions
|
||||
*
|
||||
* Yes that true, PPU memory & CPU memory work in a nearly same fashion depite
|
||||
* the fact that we actually didn't have any Read/Write hook and ReadWrite
|
||||
* protection. We even didn't need "attributes" for the page. One of the only
|
||||
* need is the "powerful" ghost system
|
||||
*/
|
||||
|
||||
int ppu_initMemory()
|
||||
{
|
||||
int page;
|
||||
for(page = 0 ; page < 0x40 ; page++)
|
||||
{
|
||||
ppu_setPagePtr(page,NULL);
|
||||
ppu_memoryGhostLink[page] = 0xFF; /* ( >= 0x40 is not possible) */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ppu_updateGhost(byte page)
|
||||
{
|
||||
byte cur_ghost;
|
||||
|
||||
cur_ghost = ppu_memoryGhostLink[page];
|
||||
if (cur_ghost < 0x40)
|
||||
ppu_memoryPages[cur_ghost] = ppu_memoryPages[page];
|
||||
}
|
||||
|
||||
void ppu_setPagePtr (byte page, byte *ptr)
|
||||
{
|
||||
ppu_memoryPages[page] = ptr;
|
||||
ppu_updateGhost(page);
|
||||
}
|
||||
|
||||
void ppu_setPagePtr1k(byte page, byte *ptr)
|
||||
{ /* 1k = 4 * 256 */
|
||||
ppu_memoryPages[page + 0] = ptr;
|
||||
ppu_memoryPages[page + 1] = ptr + 0x100;
|
||||
ppu_memoryPages[page + 2] = ptr + (0x100 * 2);
|
||||
ppu_memoryPages[page + 3] = ptr + (0x100 * 3);
|
||||
|
||||
ppu_updateGhost(page + 0);
|
||||
ppu_updateGhost(page + 1);
|
||||
ppu_updateGhost(page + 2);
|
||||
ppu_updateGhost(page + 3);
|
||||
}
|
||||
|
||||
void ppu_setPagePtr2k(byte page, byte *ptr)
|
||||
{
|
||||
ppu_memoryPages[page + 0] = ptr;
|
||||
ppu_memoryPages[page + 1] = ptr + 0x100;
|
||||
ppu_memoryPages[page + 2] = ptr + (0x100 * 2);
|
||||
ppu_memoryPages[page + 3] = ptr + (0x100 * 3);
|
||||
ppu_memoryPages[page + 4] = ptr + (0x100 * 4);
|
||||
ppu_memoryPages[page + 5] = ptr + (0x100 * 5);
|
||||
ppu_memoryPages[page + 6] = ptr + (0x100 * 6);
|
||||
ppu_memoryPages[page + 7] = ptr + (0x100 * 7);
|
||||
|
||||
ppu_updateGhost(page + 0);
|
||||
ppu_updateGhost(page + 1);
|
||||
ppu_updateGhost(page + 2);
|
||||
ppu_updateGhost(page + 3);
|
||||
ppu_updateGhost(page + 4);
|
||||
ppu_updateGhost(page + 5);
|
||||
ppu_updateGhost(page + 6);
|
||||
ppu_updateGhost(page + 7);
|
||||
}
|
||||
|
||||
void ppu_setPagePtr4k(byte page, byte *ptr)
|
||||
{
|
||||
ppu_setPagePtr2k(page, ptr);
|
||||
ppu_setPagePtr2k(page+((4 KBYTE / 256) / 2), ptr + 2 KBYTE);
|
||||
}
|
||||
|
||||
void ppu_setPagePtr8k(byte page, byte *ptr)
|
||||
{
|
||||
ppu_setPagePtr4k(page, ptr);
|
||||
ppu_setPagePtr4k(page+((8 KBYTE / 256) / 2), ptr + 4 KBYTE);
|
||||
}
|
||||
|
||||
void ppu_setPageGhost(byte page, bool value, byte ghost)
|
||||
{
|
||||
if (value == true)
|
||||
{
|
||||
ppu_memoryPages[page] = ppu_memoryPages[ghost];
|
||||
ppu_memoryGhostLink[ghost] = page;
|
||||
printf("set ghost of 0x%02X to 0x%02X (ptr: %p)\n", ghost, page, ppu_memoryGhostLink[ghost]);
|
||||
}
|
||||
}
|
||||
|
||||
void ppu_memoryDumpState(FILE *fp)
|
||||
{
|
||||
int i;
|
||||
for (i = 0x00; i < 0x40; i++)
|
||||
{
|
||||
fprintf(fp,
|
||||
"Page 0x%02X : ptr:%p ghost:0x%02X\n",
|
||||
i,
|
||||
ppu_memoryPages[i],
|
||||
ppu_memoryGhostLink[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
byte ppu_readMemory(byte page, byte addr)
|
||||
{
|
||||
byte *ptr;
|
||||
if (page == 0x3F)
|
||||
return ( ppu_memoryPages[0x3F][addr&0x1F] & 0x3F );
|
||||
|
||||
ptr = ppu_memoryPages[page & 0x3F];
|
||||
return ptr[addr];
|
||||
}
|
||||
|
||||
void ppu_writeMemory(byte page, byte addr, byte value)
|
||||
{
|
||||
byte *ptr;
|
||||
if (page == 0x3F)
|
||||
{
|
||||
/* Here we will cheat with the palette miroring, since we didn't write
|
||||
as often as we read the palette, we will mirror here */
|
||||
//printf("%s palette: color %02X new value : %02d (0x%02X%02X)\n", ((addr&0x10)< 0x10) ? "Bgnd" : "Sprt", addr&0x1F, value & 0x3F, page, addr);
|
||||
if ((addr & 0x10) == 0x00)
|
||||
{
|
||||
ppu_memoryPages[0x3F][addr&0x1F] = value;
|
||||
ppu_memoryPages[0x3F][(addr&0x1F) | 0x10] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu_memoryPages[0x3F][addr&0x1F] = value;
|
||||
if (( addr & 0x1F ) == 0x10 )
|
||||
ppu_memoryPages[0x3F][(addr&0x1F) & 0xEF] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = ppu_memoryPages[page & 0x3F];
|
||||
ptr[addr] = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
1258
src/ppu/ppu.new.c
Executable file
1258
src/ppu/ppu.new.c
Executable file
File diff suppressed because it is too large
Load Diff
1328
src/ppu/ppu.new2.c
Executable file
1328
src/ppu/ppu.new2.c
Executable file
File diff suppressed because it is too large
Load Diff
1279
src/ppu/ppu.old.c
Executable file
1279
src/ppu/ppu.old.c
Executable file
File diff suppressed because it is too large
Load Diff
75
src/utils/bin2h/bin2h.c
Executable file
75
src/utils/bin2h/bin2h.c
Executable file
@ -0,0 +1,75 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
char *infile;
|
||||
FILE *fpin = stdin;
|
||||
FILE *fpout = stdout;
|
||||
short c;
|
||||
infile = "stdin";
|
||||
if (argc > 1)
|
||||
{
|
||||
|
||||
for(i = 1; argv[i] && argv[i][0] == '-'; i++)
|
||||
{
|
||||
if (i < argc)
|
||||
{
|
||||
switch(argv[i][1])
|
||||
{
|
||||
case 'i':
|
||||
fpin = fopen(argv[i+1], "rb");
|
||||
infile = argv[i+1];
|
||||
if (fpin == NULL)
|
||||
{
|
||||
fprintf(stderr,"Error: cannot open in file '%s'\n", argv[i+1]);
|
||||
exit(-1);
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
|
||||
fpout = fopen(argv[i+1], "wb");
|
||||
if (fpout == NULL)
|
||||
{
|
||||
fprintf(stderr,"Error: cannot open out file '%s'\n", argv[i+1]);
|
||||
exit(-1);
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"Error: unknown argument: %s\n", argv[i]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fpout, "/* Generated data file from file '%s' */\n\n\n", infile);
|
||||
|
||||
fprintf(fpout, "unsigned char data[] = {\n");
|
||||
i = 0;
|
||||
while((c = fgetc(fpin)) >= 0)
|
||||
{
|
||||
if (i == 0)
|
||||
fprintf(fpout, "\t\t0x%02X", (unsigned char)c);
|
||||
else
|
||||
fprintf(fpout, ", 0x%02X", (unsigned char)c);
|
||||
|
||||
i++;
|
||||
if (i > 10)
|
||||
{
|
||||
fprintf(fpout,", \\\n");
|
||||
i = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
fprintf(fpout, "\n\t\t};\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
src/utils/sendromdata.py
Normal file
94
src/utils/sendromdata.py
Normal file
@ -0,0 +1,94 @@
|
||||
"""
|
||||
Simple TI-NESulator game database importer
|
||||
|
||||
This python application will generate a XML file on the output with all information needed to import in the TI-NESulator
|
||||
game database.
|
||||
"""
|
||||
|
||||
import sys, md5, sha, urllib, urlparse
|
||||
|
||||
|
||||
def get_page(url, post_data=None, headers=()):
|
||||
"""
|
||||
Helper method that gets the given URL, handling headers
|
||||
"""
|
||||
opener = urllib.URLopener()
|
||||
for k, v in headers:
|
||||
opener.addheader(k, v)
|
||||
try:
|
||||
f = opener.open(url, post_data)
|
||||
except IOError, e:
|
||||
if e[1] == 302:
|
||||
return '<html></html>'
|
||||
else:
|
||||
raise
|
||||
return f.read()
|
||||
|
||||
if __name__ == '__main__':
|
||||
#print "<gamelist>"
|
||||
for filename in sys.argv[1:]:
|
||||
f = open(filename)
|
||||
|
||||
|
||||
try:
|
||||
|
||||
fs = f.read()
|
||||
if fs[0:4] == "NES%c" % 0x1A:
|
||||
Flags = ord(fs[6]) & 0x0F;
|
||||
DiskDude = 0
|
||||
if fs[7:16] == "DiskDude!":
|
||||
DiskDude = 1
|
||||
|
||||
mapperID = ord(fs[6]) >> 4
|
||||
if DiskDude == 0:
|
||||
mapperID = mapperID | (ord(fs[7]) & 0xF0)
|
||||
|
||||
prgsize = ord(fs[4]) * 16 * 1024
|
||||
chrsize = ord(fs[5]) * 8 * 1024
|
||||
mirror = 0
|
||||
if Flags & 0x01:
|
||||
mirror = 1
|
||||
|
||||
sram = 0
|
||||
if Flags & 0x02:
|
||||
sram = 1
|
||||
|
||||
Trainer = 0
|
||||
if Flags & 0x04:
|
||||
Trainer = 1
|
||||
|
||||
print " <game>"
|
||||
print " <name>%s</name>" % filename
|
||||
print " <sha>%s</sha>" % sha.new(fs).hexdigest()
|
||||
print " <md5>%s</md5>" % md5.new(fs).hexdigest()
|
||||
print " <mapperID>%d</mapperID>" % mapperID
|
||||
print " <prgsize>%d</prgsize>" % prgsize
|
||||
print " <chrsize>%d</chrsize>" % chrsize
|
||||
print " <miror>%d</miror>" % mirror
|
||||
print " <sram>%d</sram>" % sram
|
||||
print " <trainer>%d</trainer>" % Trainer
|
||||
print " <diskdude>%d</diskdude>" % DiskDude
|
||||
print " </game>"
|
||||
|
||||
|
||||
#will fill the DB :
|
||||
url = "http://127.0.0.1/~mtrapier/nesstat/add.php"
|
||||
|
||||
html = get_page(url, urllib.urlencode({
|
||||
'n': filename,
|
||||
'md5': md5.new(fs).hexdigest(),
|
||||
'sha1': sha.new(fs).hexdigest(),
|
||||
'm': mapperID,
|
||||
'prg': prgsize,
|
||||
'chr': chrsize,
|
||||
'mir': mirror,
|
||||
'sram': sram,
|
||||
't': Trainer,
|
||||
'd': DiskDude,
|
||||
}))
|
||||
|
||||
print html
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
#print "</gamelist>"
|
||||
56
unix/Makefile
Executable file
56
unix/Makefile
Executable file
@ -0,0 +1,56 @@
|
||||
CC = gcc
|
||||
|
||||
#For Debug
|
||||
#CFLAGS = -g `allegro-config --cflags debug` -I../src -Wall -pg -DISPAL -DNO_DECIMAL -DUNIX -DFAST_RDOP -DLSB_FIRST -DUSE_SOUND
|
||||
|
||||
#For Retail
|
||||
CFLAGS = -I$(SRC)/include -I$(SRC) -g `allegro-config --cflags release`l -DISNTSC -DNO_DECIMAL -DUNIX -DFAST_RDOP -DLSB_FIRST -DDEBUG -DUSE_SOUND
|
||||
# -fomit-frame-pointer -funroll-loops
|
||||
#-DNO_N_KEY
|
||||
#-DUSE_SOUND
|
||||
#-DDETECT_BUS_CONFLICT
|
||||
#-DISNTSC or -DISPAL
|
||||
#-DDEBUG
|
||||
|
||||
LDFLAGS = `allegro-config --libs debug` -lpthread
|
||||
#-pg #-lefence
|
||||
#debug` -lpthread -lefence -pg
|
||||
#release` -lpthread
|
||||
#-pg
|
||||
|
||||
SRC=../src
|
||||
PLUGINS_DIR=pluginsmanager/plugins/
|
||||
MAPPERS_DIR=mappersmanager/mappers/
|
||||
|
||||
PLUGINS=$(shell ls $(SRC)/$(PLUGINS_DIR)/*.c)
|
||||
MAPPERS=$(shell ls $(SRC)/$(MAPPERS_DIR)/*.c)
|
||||
|
||||
all: tines
|
||||
|
||||
tines: tines.a corecpu.a apu.a ppu.a plugins.a mappers.a memory.a
|
||||
$(CC) -o $@ $(LDFLAGS) $^
|
||||
|
||||
apu.a: $(SRC)/apu/Sound.c $(SRC)/apu/SndAlleg.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
corecpu.a: $(SRC)/corecpu/Debug.c $(SRC)/corecpu/M6502.c
|
||||
$(CC) $(CFLAGS) -Wno-pointer-sign -c $^ -o $@
|
||||
|
||||
tines.a: $(SRC)/main.c $(SRC)/paddle.c $(SRC)/NESCarts.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
memory.a: $(SRC)/memorymanager/memory.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
ppu.a: $(SRC)/ppu/ppu.c $(SRC)/ppu/ppu.memory.c $(SRC)/ppu/debug/ppu.debug.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
mappers.a: $(SRC)/mappersmanager/manager.c $(SRC)/mappersmanager/utils.c $(MAPPERS)
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
plugins.a: $(SRC)/pluginsmanager/manager.c $(PLUGINS)
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -Rf *.o *~ core
|
||||
Loading…
x
Reference in New Issue
Block a user