Documentation VinaceIntroductionVinace est pour VINtage Apple Computer Emulator. Pour l'instant ce n'est
qu'un émulateur d'Apple //e 64Ko. Il devrait pouvoir facilement évoluer vers un
émulateur d'Apple ][ tout modèle.Ce document comporte deux parties. La partie Utiliser Vinace
explique comment utiliser Vinace et la partie A l'intérieur de Vinace
parle du fonctionnement de Vinace.Ce document est encore en cours d'écriture, ce n'est pas une version finale.
Beaucoup d'informations peuvent manquer.Utiliser VinaceDémarrage rapideSi vous êtes pressé, voici les instructions pour utiliser Vinace.Pour démarrer Vinace, lancez simplement vinace
depuis l'intérieur de son répertoire.Pour que l'Apple arrête de lire depuis le disque, pressez Ctrl
- Pause. Pour redémarrer l'Apple, pressez simultanément
Alt gauche - Ctrl - Pause.Pour insérer un disque, glissez un fichier d'image disque sur le lecteur
de disquette.ClavierVoici les touches du clavier original de l'Apple //e :
Touches du clavier de l'Apple //eGroupeTouchesLettresA à Z (majuscules, minuscules et contrôle)Nombres0 à 9Symbols! @ # $ % ^ & * ( ) - _ + = { } [ ] : ; " ' ~ `| \ < > , . ? /Autres touchesEsc, Tab, Retour, Del, Flèches (gauche, droite, bas, haut)Touches spécialesReset, Pomme ouverte, Pomme pleine
Le clavier virtuel de l'Apple est associé au clavier de votre ordinateur.
Les lettres (majuscules, minuscules et contrôles), les nombres, les symboles et les
autres touches sont directement connectés au touches correspondantes.Les touches Pomme ouverte et
Pomme pleine sont connectées aux touches Alt
gauche et Alt droite.La combinaison de touches Ctrl - Reset est
connectée à la combinaison Ctrl - Pause (la touche
Reset seule n'a aucun effet sur le clavier de l'Apple).Ceci signifie que, si vous voulez redémarrer l'Apple //e, vous devez
presser Alt gauche - Ctrl - Pause là où, sur le clavier
original, vous pressiez Pomme ouverte - Ctrl - Reset.JoystickDans Vinace, il y a une émulation d'un joystick simple, utilisant le pavé
numérique. En réalité, le joystick de l'Apple est capable de détecter 256 positions
sur chaque axe. Le joystick Vinace n'est capable de simuler que trois positions
sur chaque axe (0, 128 et 255). Ceci doit convenir pour la plupart des jeux mais
ne sera pas suffisant pour ceux faisant un usage précis du joystick.La touche "5" du pavé numérique est la position centrale. La touche "8"
est pour le haut, la touche "2" pour le bas, la touche "4" pour la gauche et la "6"
pour la droite. Les touches en diagonale (7, 9, 1 et 3) fonctionnent aussi.Il n'y a pas encore d'émulation des boutons, la touche Alt
gauche doit donc être utilisée pour le bouton 0 et Alt
droite pour le bouton 1.Disquettes et lecteursLes lecteurs de disquette dans Vinace sont faciles à utiliser.Pour ouvrir ou fermer le lecteur, cliquez simplement sur le fermoir.Pour insérer une disquette dans un lecteur, glissez le fichier image disque
sur le lecteur. En cas de succès, le nom de la disquette va apparaître sur le lecteur
et il se refermera automatiquement.Seuls les fichiers .dsk (Images disque en ordre
DOS) sont supportés pour l'instant. D'autres formats (images disque en ordre ProDOS,
images nibbles) seront supportés plus tard.L'écriture sur disque n'est pas encore implémentée.Des images disque peuvent être trouvées sur le dépôt Asimov, dans la
section Images ici :
ftp://ftp.apple.asimov.net/pub/apple_II/images/A l'intérieur de VinacePrincipes générauxAvant d'aller plus profond dans Vinace, voici, en tant qu'introduction,
quelques principes généraux.Pourquoi un nouvel émulateur ?Les émulateurs existant ont une interface graphiques vieille et peu pratique
(pas d'utilisation de la souris, ligne de commande pour changer de disquette).Les émulateurs existants sont écrits pour être performants et pas pour être
compréhensibles ou modulaires.Les émulateurs existants sont monolithiques, pas assez proche du matériel original
et pas très facile à faire évoluer.Je souhaitais développer un projet pas trop difficile pour me remettre au C++.Qu'est-ce qu'un ordinateur ?Fondamentalement, un ordinateur c'est un processeur (CPU), de la mémoire, et des périphériques.Le processeur est le composant central de l'ordinateur. Il récupère des données depuis la mémoire,
il les traite et remet le résultat dans la mémoire. Le processeur peut recevoir des signaux, comme le signal de remise à zéro (reset) ou les interruptions.
Il reçoit aussi un signal périodique de l'horloge lui indiquant quand un cycle doit être effectué (une instruction
est "faite" de plusieurs cycles).A part les signaux, la seule communication entre le processeur et le reste du monde s'effectue
via la mémoire. Comme différent types de mémoire sont disponibles (RAM, ROM, etc.), un bus mémoire est
chargé d'interfacer le processeur avec ces différent types. Selon l'adresse demandée par le processeur,
le bus transfert la requête à la mémoire correspondante.Pour piloter les périphériques, le processeur utilise la mémoire (une fois encore, c'est la seule
porte vers le monde extérieur). Un type de mémoire spécifique, l'unité d'entrée sortie (IOU), est connectée
au bus mémoire. L'unité d'entrée sortie n'est pas réellement une mémoire puisqu'elle ne stocke pas
d'information. Quand une adresse est accédée dans l'IOU, cela active quelque chose dans un périphérique
ou lit une information en provenance de ce périphérique. Par exemple, l'accès à l'adresse 15 peut activer
une lumière, ou bien l'accès à l'adresse 17 peut lire l'état d'un bouton. C'est en gros comme ça que le
processeur interagit avec les périphériques.Si nous mettons tout cela ensemble, nous obtenons un schéma "simple" de ce qu'est un ordinateur :Le rectangle orage, contenant le processeur, la mémoire et l'unité d'entrée sortie mais
ni les périphériques, ni l'horloge, représente ce que j'ai appelé le "noyau" (core). Le noyau
est la partie minimale pour que l'ordinateur fonctionne. Les périphériques ne font que connecter
l'ordinateur au monde et, en particulier, à l'utilisateur, mais ils ne sont pas indispensables.
J'ai mis l'horloge en dehors car je considère l'horloge comme une interface entre l'ordinateur et
le temps réel. On peut modifier la fréquence de l'horloge sans affecter le comportement de
l'ordinateur. On peut même utiliser une horloge manuelle pour étudier l'ordinateur pas à pas.Le modèle d'émulateur à trois couchesJe voulais avoir un émulateur modulaire qui soit flexible pour lequel il
soit facile de développer de nouvelles fonctionnalités. Je voulais aussi quelque chose
qui soit très près de la réalité. Par exemple, je voulais être capable de développer
un nouveau périphérique que je pourrais "brancher" dans mon émulateur, de la même façon
que l'on branche des périphériques dans une machine.J'ai décidé d'utiliser un modèle à trois couches. Voici ces trois couches dans un schéma :Couche noyauLa couche noyau (core) contient tous les composants, et seulement eux,
nécessaires pour avoir un ordinateur qui fonctionne. Cela signifie que l'on
peut instancier un noyau seul et jouer avec lui. C'est intéressant dans un
but d'étude mais cela donne un ordinateur sourd et aveugle. Le noyau peut
être vu comme l'ordinateur vu depuis l'intérieur de lui même (dans cette
couche, les programmes tournent comme s'ils étaient dans un ordinateur
réel).Couche matérielLa couche matériel (hardware) est la représentation logicielle
de l'ordinateur émulé. Cette représentation est indépendante de l'interface
graphique. Par exemple, la sortie vidéo est représentée par une matrice de
pixels et le bouton d'un joystick par un simple booléen.Cette couche doit contenir la représentation de tous les objets du
monde émulé, comme les disquettes ou les cartouches. Elle doit aussi contenir
toute la logique de l'émulateur de façon à ce que la couche suivante ne soit
en charge que de l'interface homme machine.Couche IHMLa couche Interface Homme-Machine (GUI) est chargée de représenter à
l'utilisateur la couche matériel.ProcesseurLe processeur est un dispositif capable d'exécuter une séquence d'instructions
stockées en mémoire. Ces instructions peuvent nécessiter l'usage de registres (petit
morceaux de mémoire interne). Elles peuvent aussi nécessiter la lecture et l'écriture
en mémoire.La périodicité de l'exécution des instruction est controllée par une horloge
indiquant au processeur quand il doit effectuer un cycle. Un cycle est une partie
d'instruction : décodage de l'instruction, récupération des données depuis la mémoire,
écriture en mémoire, etc. Le nombre de cycles pour une instruction dépend de sa
complexité.Le processeur peut aussi réagir à certains signaux externes comme le
signal de remise à zéro (reset) et les demandes d'interruption. Ces signaux sont
habituellement émis par les périphériques.Donc, un processeur a trois types d'interaction avec le monde extérieur :Lecture et écriture en mémoireRequête de cycle par l'horlogeSignauxDans Vinace, les processeur sont représentés par des classes héritant de
la classe CProcessor.Pour créer un nouveau processeur, une classe enfant doit être créée et les
méthodes suivantes doivent être implémentées :Constructeur: le constructeur de
CProcessor prend deux paramètre : la mémoire qui
doit être liée au processeur et un nombre de signaux. Le constructeur de la classe
enfant doit appeler celui de CProcessor avec un
nombre donnée de signaux. C'est le nombre de signaux possibles différents. Par
exemple, pour un processeur n'ayant que le signal de remise à zéro, ce nombre
est 1.reset(): cette méthode est censée
remettre l'état du processeur à zéro. Elle est appelée une fois lorsque le processeur
est instancié. C'est à la classe enfant de connecter le signal de remise à zéro à cette
méthode.process_instruction(): cette méthode
est censée traiter l'instruction suivante. Elle est appelée par
cycle() une fois les cycles de l'instruction
précédente terminés. process_instruction()
doit augmenter le membre cycles du bon nombre de
cycles correspondant à l'instruction.process_signals(): Cette méthode est
censée traiter les signaux. Elle est appelée par
cycle(). Elle doit renvoyer faux si un signal
a été traité et vrai s'il n'y avait pas de signal à traiter. Dans ce cas,
cycle() appelle alors
process_instruction.MémoireUne mémoire est un composant capable d'être lu et écrit.Dans Vinace, la classe qui représente la mémoire est CMemory. Un objet
CMemory n'a pas à retenir quoi que ce soit en réalité. Par exemple,
CDummyMemory, une classe enfant de CMemory, est une mémoire qui
renvoie des valeurs bidon. Elle est utilisée pour remplir les espaces mémoire non connectés.La RAM et la ROM sont représentées par les classes CRamMemory et
CRomMemory, enfants de CMemory.Proxys mémoireLes proxys mémoire, représentés par la classe CMemoryProxy, sont des
proxys qui permettent d'adresser une partie d'un objet CMemory. En réalité, ils ne font
que décaler l'adresse selon l'adresse de départ de la cible.Bus mémoireLes bus mémoire sont des enfants de CMemory qui dispatchent les requêtes de lecture et d'écriture
vers des sous-mémoire selon l'adresse de la requête ou selon des drapeaux d'un objet
CUnit. Il n'y a pas de classe commune pour les bus mémoire car
ils n'ont rien de spécifique en commun, à part le fait qu'ils soient des mémoires.La mémoire de l'Apple //eVoici un schéma de la mémoire d'un Apple //e 64Ko.Le processeur accède seulement au bus mémoire principal (main memory bus). l'IOU est l'unité d'entrée/sortie.Il y a un banc de 64Ko de RAM et plusieurs bancs de ROM :La ROM de la carte language (LC ROM) contient les routines moniteur et celles du basic
(Applesoft sur le //e, Integer sur le ][+). Elle est visible dans l'espace $D000-$FFFF.La ROM interne contient des routines additionnelles pour le //e.Les ROM des cartes périphériques (card ROM) sont les ROMs des cartes d'extension.Voici une explication de chacun des bus.Bus mémoire principal (Main memory bus)Ce bus est la partie visible de la mémoire (depuis le point de vue du processeur).
Ce bus divise la mémoire en quatre parties :$0000-$BFFF est connecté à la RAM.$C000-$C0FF est connecté à l'unité d'entrée sortie (IOU).$C100-$CFFF est connecté au bus de la ROM E/S (peut être connecté à la ROM des
cartes périphériques ou bien à la ROM interne).$D000-$FFFF est connecté au bus de la carte langage (habituellement, la ROM principale est visible ici).Bus de la carte language (Language Card bus)Référence : Apple IIe Technical Reference Manual pages 79 to 83
(PDF pp113-117)Le bus de la carte langage est en charge des 12Ko les plus hauts de la mémoire. Cet espace était
originellement dédié à la ROM Basic et moniteur dans les Apple ][ 48Ko. Sur les Apples 64Ko,
une nouvelle possibilité était d'adresser de la RAM dans cet espace. Cette fonctionnalité est utilisé pour
charger des langages alternatifs en mémoire (comme le basic Integer du ][+ sur un //e).La lecture et l'écriture peuvent être modifiés indépendamment. Ceci permet d'écrire en
RAM pendant que la ROM est visible. C'est particulièrement pratique lorsque l'on prépare la RAM car
bien des routines bas niveau sont en ROM (affichage du texte, lecture du clavier...).Comme 16Ko de RAM sont disponibles mais l'espace ne fait que 12Ko, les 4Ko inférieurs
($D000-$FFFF) peuvent adresser deux bancs de RAM. Les 8Ko supérieurs sont toujours connectés
à la même RAM.Ce bus est piloté par l'Unité de carte langage
en utilisant les interrupteurs logiciels LCRAM, LCWRITE et
LCBNK2.Par défaut (LCRAM et LCWRITE sur off),
la ROM est lisible et les écritures n'ont aucun effet.Les requêtes d'écriture sont transmises à la RAM si LCWRITE est actif. Sinon,
les requête d'écriture n'ont pas d'effet (comme pour une ROM).Les requêtes de lecture sont transmises à la RAM si LCRAM est actif et
à la ROM sinon.Les 8Ko supérieurs ($E000-$FFFF) sont connectés aux 8Ko supérieurs de la RAM
($E000-$FFFF).Les 4Ko inférieurs ($D000-$DFFF) sont connectés à la RAM en $D000-$DFFF si
LCBNK2 est actif ou à celle en $C000-$CFFF sinon.Bus de la ROM E/S (I/O Rom Bus)L'Apple //e et les modèles suivants ont plus que 12Ko de ROM. Pour accéder au reste de
la ROM, l'espace $C100-$CFFF, habituellement réserver aux ROM des cartes périphériques peut
être utilisé. Une fenêtre, en $C300-$C3FF, correspondant à la carte 80 colonnes, peut être
sélectionnée spécifiquement.Ce bus est piloté par l'unité de ROM E/S en utilisant
les interrupteurs logiciels CXROM et C3ROM.Si CXROM est actif, les requêtes sont transmises au
bus des ROM périphériques. Si
CXROM est actif, la ROM interne est visible.C3ROM permet de voir la ROM interne en $C300-$C3FF
quelque soit l'état de CXROM. Ceci est utilisé pour masquer
la ROM de la carte d'extension 80 colonnes et pour utiliser les routines internes à la place. Bus des ROM périphériques (Slot ROM Bus)Chaque carte d'extension peut avoir 256 octets de ROM basique
plus une extension ROM de 4Ko. La ROM basique est visible en $Cn00-$CnFF,
où n est le numéro du port.Lorsque la ROM basique est lue, l'extension ROM (s'il y en a une)
est sélectionnée et devient visible en $C800-$CFFF. $CFFF est aussi un
interrupteur logiciel (nommée CLRROM) qui désélectionne la ROM.Ceci est expliqué dans le Apple IIe Technical Reference Manual
page 132.Le bus des ROM périphériques est en charge de transférer les requêtes
de lecture à la bonne ROM. Comme l'unité des ports d'extension,
il doit être informé des insertions et retraits de cartes.Insérer et retirer des cartesLa méthode insert_card indique
au bus qu'une carte a été insérée :void CSlotRomBus::insert_card(int slot, CMemory *cardRom, CMemory *cardRomExt)slot est le numéro du port (1-7).
cardRom est la ROM basique de la carte et
cardRomExt est sont extension.La méthode remove_card indique
au bus qu'une carde a été retirée :void CSlotRomBus::remove_card(int slot)slot est le numéro du port (1-7). Fichiers de ROMLes fichiers d'image des ROM sont nécessaire aux émulateurs mais ils
sont sous copyright et ne peuvent être distribués librement. Un bon endroit
pour récupérer des images de ROM est la section émulateurs du
dépôt Asimov.Vinace a besoin des ROM internes ainsi que de la ROM du Disk II
si un contrôleur Disk II est branché. Voici une description des fichiers de ROM
utilisés par Vinace.apple_iie_rom.zipEmplacement : ftp://ftp.apple.asimov.net/pub/apple_II/emulators/rom_images/apple_iie_rom.zipContient un seul fichier : APPLE2E.ROM
Carte du fichier APPLE2E.ROMDeÀDescription0x00000x01ffVide0x02000x02ffInconnu, probablement la ROM d'un périphérique en port 20x03000x05ffVide0x06000x06ffROM 16 secteurs du contrôleur Disk II0x07000x0fffVide0x10000x3fffROM de l'Integer Basic ?0x40000x40ffVide0x41000x4fffROM interne $C100-$CFFF0x50000x7fffROM principale $D000-$FFFF ROM
apple_ii_rom.zipEmplacement : ftp://ftp.apple.asimov.net/pub/apple_II/emulators/rom_images/apple_ii_rom.zipIdentique à apple_iie_rom.zip.apple_ii+_rom.zipEmplacement : ftp://ftp.apple.asimov.net/pub/apple_II/emulators/rom_images/apple_ii+_rom.zipContient un seul fichier : APPLE2.ROM
Carte du fichier APPLE2.ROMDeÀDescription0x00000x05ffVide0x06000x06ffROM 16 secteurs du contrôleur Disk II0x07000x0fffVide0x10000x15ffVide0x16000x16ffROM 16 secteurs du contrôleur Disk II0x20000x4fffROM principale $D000-$FFFF ROM
Entrées / SortiesL'unité d'entrées/sorties du ][+
Adresses de l'unité d'entrées/sorties de l'Apple ][+AdrNomAccèsDescriptionUnitéC000KBDRDernière touche presséeClavierC010KBDSTRBRWRemise à zéro du clavierClavierC020TAPEOUTR7Bascule la sortie cassetteCassetteC030SPKRRBascule l'état du haut parleurHaut parleurC040STROBEREnvoie une impulsion sur la sortie jeuxJeuC050TXTCLRWRMode graphiqueMode graphiqueC051TXTSETWRMode texteMode graphiqueC052MIXCLRWRMode plein écranMode graphiqueC053MIXSETWRMode mixteMode graphiqueC054TXTPAGE1WRAffiche la page 1Mode graphiqueC055TXTPAGE2WRAffiche la page 2Mode graphiqueC056LORESWRGraphiques basse résolutionMode graphiqueC057HIRESWRGraphiques haute résolutionMode graphiqueC058CLRAN0WRMise à 0 de l'annonciateur 0JeuC059SETAN0WRMise à 1 de l'annonciateur 0JeuC05ACLRAN1WRMise à 0 de l'annonciateur 1JeuC05BSETAN1WRMise à 1 de l'annonciateur 1JeuC05CCLRAN2WRMise à 0 de l'annonciateur 2JeuC05DSETAN2WRMise à 1 de l'annonciateur 2JeuC05ECLRAN3WRMise à 0 de l'annonciateur 3JeuC05FSETAN3WRMise à 1 de l'annonciateur 3JeuC060TAPEINR7Lit l'état de l'entrée cassetteCassetteC061PB0R7Bouton poussoir 0JeuC062PB1R7Bouton poussoir 1JeuC063PB2R7Bouton poussoir 2JeuC064PADDL0R7Lit l'entrée analogique 0JeuC065PADDL1R7Lit l'entrée analogique 1JeuC066PADDL2R7Lit l'entrée analogique 2JeuC067PADDL3R7Lit l'entrée analogique 3JeuC070PTRIGRRemise à zéro des entrées analogiquesJeuC080RLecture de la RAM page 2, pas d'écritureCarte langageC081RRLecture de la ROM, écriture de la RAM page 2Carte langageC082RLecture de la ROM, pas d'écritureCarte langageC083RRLecture et écriture en RAM page 2Carte langageC084-C087Identique à C080-C083Carte langageC088RLecture de la RAM page 1, pas d'écritureCarte langageC089RRLecture de la ROM, écriture de la RAM page 1Carte langageC08ARLecture de la ROM, pas d'écritureCarte langageC08BRRLecture et écriture en RAM page 1Carte langageC08C-C08FRIdentique à C088-C08BCarte langageC090-C09FAdresses pour le port d'extension 1Ports d'extensionC0A0-C0AFAdresses pour le port d'extension 2Ports d'extensionC0B0-C0BFAdresses pour le port d'extension 3Ports d'extensionC0C0-C0CFAdresses pour le port d'extension 4Ports d'extensionC0D0-C0DFAdresses pour le port d'extension 5Ports d'extensionC0E0-C0EFAdresses pour le port d'extension 6Ports d'extensionC0F0-C0FFAdresses pour le port d'extension 7Ports d'extension
R - Lire pour agir ou récupérer l'information, W - Écrire pour agir, RR - Lire deux fois pour agir, R7 - Lire l'information dans le bit 7L'unité d'entrées/sorties du //eL'unité d'entrées/sorties de l'Apple //e est basée sur celle de l'Apple ][+, sauf pour les adresses TXTPAGE1
et TXTPAGE2 qui sont gérées par l'unité AuxMemory (qui passe la requête à l'unité GraphicMode).
L'unité d'entrées/sorties de l'Apple //e I/O possède quelques interrupteurs logiciels supplémentaires ainsi que
des accès à l'état des interrupteurs existants.
Adresses de l'unité d'entrées/sorties de l'Apple //eAdrNomAccèsDescriptionUnitéC000KBDRDernière touche presséeClavierC00080STOREOFFWUtilise $C002-$C005 pour la mémoire auxiliaireMémoire auxiliaireC00180STOREONWUtilise PAGE2 pour la mémoire auxiliaireMémoire auxiliaireC002RDMAINRAMWSi 80STORE est à 0: Lit la mémoire principale en $0200-$BFFFMémoire auxiliaireC003RDCARDRAMWSi 80STORE est à 0: Lit la mémoire auxiliaire en $0200-$BFFFMémoire auxiliaireC004WRMAINRAMWSi 80STORE est à 0: Écrit la mémoire principale en $0200-$BFFFMémoire auxiliaireC005WRCARDRAMWSi 80STORE est à 0: Écrit la mémoire principale en $0200-$BFFFMémoire auxiliaireC006SETSLOTCXROMWROM des périphériques ($C100-$CFFF)Rom E/SC007SETINTCXROMWROM interne ($C100-$CFFF)Rom E/SC008SETSTDZPWPile et page zéro principalesMémoire auxiliaireC009SETALTZPWPile et page zéro auxiliairesMémoire auxiliaireC00ASETINTC3ROMWROM interne en $C300-$C3FFRom E/SC00BSETSLOTC3ROMWROM des périphériques $C300-$C3FFRom E/SC00CCLR80VIDW40 ColonnesMode texteC00DSET80VIDW80 ColonnesMode texteC00ECLRALTCHARWSélectionne la police de caractère primaireMode texteC00FSETALTCHARWSélectionne la police de caractère alternativeMode texteC010KBDSTRBRWRemise à zéro du clavierClavierC011RDLCBNK2R7État de visibilité de la page 1 (0) ou de la page 2 (1) de RAM en $D000-DFFF LanguageCardC012RDLCRAMR7État de visibilité de la ROM (0) our de la RAM() en $D000-$FFFFLanguageCardC013RDRAMRDR7État de lecture de la RAM principale/auxiliaireMémoire auxiliaireC014RDRAMWRTR7État d'écriture dans la RAM principale/auxiliaireMémoire auxiliaireC015RDCXROMR7État de l'accès à la ROM des périphériques (0) ou interne (1)Rom E/SC016RDALTZPR7État de la pile et de la page zéro principale ou auxiliaireMémoire auxiliaireC017RDC3ROMR7État de la ROM visible en $C300-$C3FF : Port 3 (0) ou Port auxiliaire (1)Rom E/SC018RD80STORER7État de 80STOREOFFMémoire auxiliaireC019RDVBLR7État de l'effacement vertical (1=en cours d'affichage)C01ARDTEXTR7État du mode Texte (1) ou Graphique (0)Mode graphiqueC01BRDMIXEDR7État du mode plein écran (0) ou mode mixte (1)Mode graphiqueC01CRDPAGE2R7État de l'affichage de la page 1 (0) ou page 2 (1)Mode graphiqueC01DRDHIRESR7État de la résolution basse (0) ou haute (1)Mode graphiqueC01ERDALTCHARR7État de la police de caractère primaire ou alternativeMode texteC01FRD80VIDR7État de l'affichage 40 ou 80 colonnesMode texteC020TAPEOUTR7Bascule la sortie cassetteCassetteC030SPKRRBascule l'état du haut parleurSpeakerC040STROBEREnvoie une impulsion sur la sortie jeuxGameC050TXTCLRWRMode graphiqueMode graphiqueC051TXTSETWRMode texteMode graphiqueC052MIXCLRWRMode plein écranMode graphiqueC053MIXSETWRMode mixteMode graphiqueC054TXTPAGE1WRAffiche la page 1Mode graphiqueC055TXTPAGE2WRSi 80STORE est à 0: Affiche la page 2, Si 80STORE est à un: Écriture/Lecture de la mémoire auxiliaire d'affichageAuxMemory, GraphicModeC056LORESWRGraphiques basse résolutionMode graphiqueC057HIRESWRGraphiques haute résolutionMode graphiqueC058CLRAN0WRMise à 0 de l'annonciateur 0JeuC059SETAN0WRMise à 1 de l'annonciateur 0JeuC05ACLRAN1WRMise à 0 de l'annonciateur 1JeuC05BSETAN1WRMise à 1 de l'annonciateur 1JeuC05CCLRAN2WRMise à 0 de l'annonciateur 2JeuC05DSETAN2WRMise à 1 de l'annonciateur 2JeuC05ECLRAN3WRMise à 0 de l'annonciateur 3JeuC05FSETAN3WRMise à 1 de l'annonciateur 3JeuC060TAPEINR7Lit l'état de l'entrée cassetteCassetteC061PB0R7Bouton poussoir 0 / Touche Pomme OuverteJeuC062PB1R7Bouton poussoir 1 / Touche Pomme PleineJeuC063PB2R7Bouton poussoir 2 / Touche Shift (sur certains modèles)JeuC064PADDL0R7Lit l'entrée analogique 0JeuC065PADDL1R7Lit l'entrée analogique 1JeuC066PADDL2R7Lit l'entrée analogique 2JeuC067PADDL3R7Lit l'entrée analogique 3JeuC070PTRIGRRemise à zéro des entrées analogiquesJeuC073BANKSELWSélection du banc de mémoire si plus de 128KC07FRDDHIRESR7État du graphique en Double Haute RésolutionC080RLecture de la RAM page 2, pas d'écritureCarte langageC081RRLecture de la ROM, écriture de la RAM page 2Carte langageC082RLecture de la ROM, pas d'écritureCarte langageC083RRLecture et écriture en RAM page 2Carte langageC084-C087Identique à C080-C083Carte langageC088RLecture de la RAM page 1, pas d'écritureCarte langageC089RRLecture de la ROM, écriture de la RAM page 1Carte langageC08ARLecture de la ROM, pas d'écritureCarte langageC08BRRLecture et écriture en RAM page 1Carte langageC08C-C08FRIdentique à C088-C08BCarte langageC090-C09FAdresses pour le port d'extension 1Ports d'extensionC0A0-C0AFAdresses pour le port d'extension 2Ports d'extensionC0B0-C0BFAdresses pour le port d'extension 3Ports d'extensionC0C0-C0CFAdresses pour le port d'extension 4Ports d'extensionC0D0-C0DFAdresses pour le port d'extension 5Ports d'extensionC0E0-C0EFAdresses pour le port d'extension 6Ports d'extensionC0F0-C0FFAdresses pour le port d'extension 7Ports d'extension
R - Lire pour agir ou récupérer l'information, W - Écrire pour agir, RR - Lire deux fois pour agir, R7 - Lire l'information dans le bit 7Unités d'entrées/sortiesLes unités d'E/S sont des interfaces entre la mémoire de l'Apple et les périphériques.
Dans l'émulateur, c'est une interface entre les couches noyau et matériel.Classe unitéLes unités sont représentés par des classes descendantes de la classe CUnit.Du côté mémoire de l'Apple, seules deux méthodes sont utilisées : read (lecture) et write (ecriture).
C'est à peu près la même chose que pour une mémoire excepté que l'adressage est en 8 bits au lieu de 16.Du côté périphérique, il n'y a pas de spécification. La plupart des
unités ne comportent que des interrupteurs logiciels. A chaque interrupteur
correspoind une méthode
get_<switch> et, si modifiable, une
méthode set_<switch>, où
<switch> est le nom de l'interrupteur
en minuscules.Les unités ont une méthode reset
qui est censée remettre à zéro l'unité. Elle est appelée à l'instanciation de
l'unité mais aussi lorsque l'utilisateur appuie sur le bouton "reset" (ça c'est
dans la couche matériel).Toutes les unités sont observables et doivent notifier de tout changement
pouvant subvenir. Les objets de la couche matériel doivent observer les unités pour
être informés de ce qu'il se produit.Clavier (Keyboard)Compatibilité : Tous modèles.Cette unité est en charge du clavier. Sur les Apple II, il n'y avait
pas de tampon clavier. Cette unité ne peut donc gérer qu'une touche à la fois.Méthodesvoid press_key(BYTE key);Indique à l'unité quelle touche est en train d'être pressée. Notez que
si la touche précédente n'a pas encore été lue, elle sera oubliée. Les codes
de touche doivent être en code ASCII Apple.void release_key();Indique à l'unité que la touche a été relâchée.bool key_waiting();Indique s'il y a une touche en attende de lecture par l'Apple. Cette
méthode peut être particulièrement utile pour développer un tampon clavier
ou un outil de copier coller.AddressesAdresseNomAccèsEffet0x00KBDRBits 0-6 : Dernière touche pressée ou en train de l'être. Bit 7 : est à 1 si une touche a été pressée depuis la dernière remise à zéro.0x10KBDSTROBERWRemet à zéro le clavier. Bits 0-6 : Dernière touche pressée ou en train de l'être. Bit 7 : à 1 si une touche est enfoncée.Cassette (Tape)Compatibilité : Tous modèles.Malheureusement cette unité n'est pas encore implémentée.Haut parleur (Speaker)Compatibilité : Tous modèles.Le haut parleur de l'Apple est plutôt basique : il n'a que deux niveau.
Le niveau du haut parleur est inversé en accédant à l'interrupteur logiciel SPKR.
Du côté périphérique, le niveau du haut parleur peut être lu.InterrupteursInterrupteurOffOnSPKRHaut parleur au niveau basHaut parleur au niveau hautAdressesAdresseNomAccèsEffet0x30SPKRRWChange l'état de SPKRJeu (Game)Compatibilité : Tous modèles (sauf peut être le //c).L'unité de jeu possède trois sortes de dispositif : Trois boutons poussoirs,
quatre annonciateurs et quatre entrées analogiques.Les boutons poussoirs sont connectés à ceux du joystick ou des paddles.
A partir du //e, le bouton 0 est aussi connecté à la touche du clavier Pomme
Ouverte et le bouton 1 à la touche Pomme Pleine. Sur certains modèles de //e,
le bouton 2 était connecté à la touche Shift.Les annonciateurs sont des sorties sur la prise jeu, capable de sortir à
deux niveaux (ils n'ont pas été beaucoup utilisé, peut être pas du tout).Les entrées analogiques sont connectées aux axes X et Y du joystick
(habituellement, les entrées 0 et 1) ou aux paddles. Ces entrées analogiques
fonctionnaient en mesurant le temps de décharge d'un condensateur dans le
potentiomètre du joystick ou de la paddle. L'unité n'est capable que de déclencher
la charge du condensateur et de détecter lorsqu'il est déchargé. La mesure de
temps est effectuée par un programme en ROM.Il est important de simuler ce mécanisme car certains programmes
implémentent leur propre routine de mesure. La difficulté est qu'il est important
de synchroniser le simulateur à l'horloge pour que le décompte de cycles, vu
depuis l'intérieur, soit correct.InterrupteursInterrupteurOffOnAN0Annonciateur 0 au niveau basAnnonciateur 0 au niveau hautAN1Annonciateur 1 au niveau basAnnonciateur 1 au niveau hautAN2Annonciateur 2 au niveau basAnnonciateur 2 au niveau hautAN3Annonciateur 3 au niveau basAnnonciateur 3 au niveau hautPB0Bouton 0 relâchéBouton 0 appuyéPB1Bouton 1 relâchéBouton 1 appuyéPB2Bouton 2 relâchéBouton 2 appuyéPADDL0Condensateur de l'entrée 0 déchargéCondensateur de l'entrée 0 chargéPADDL1Condensateur de l'entrée 1 déchargéCondensateur de l'entrée 1 chargéPADDL2Condensateur de l'entrée 2 déchargéCondensateur de l'entrée 2 chargéPADDL3Condensateur de l'entrée 3 déchargéCondensateur de l'entrée 3 chargéPTRIGLes condensateurs sont en déchargeLes condensateurs sont en chargeAdressesAdresseNomAccèsEffet0x58CLRAN0WRÉteint AN00x59SETAN0WRAllume AN00x5ACLRAN1WRÉteint AN10x5BSETAN1WRAllume AN10x5CCLRAN2WRÉteint AN20x5DSETAN2WRAllume AN20x5ECLRAN3WRÉteint AN30x5FSETAN3WRAllume AN30x61PB0R7Lit l'état de PB00x62PB1R7Lit l'état de PB10x63PB2R7Lit l'état de PB20x64PADDL0R7Lit l'état de PADDL00x65PADDL1R7Lit l'état de PADDL10x66PADDL2R7Lit l'état de PADDL20x67PADDL3R7Lit l'état de PADDL30x70PTRIGRDéclenche la charge des condensateurs** : Quand la charge est déclenchées, PTRIG passe à vrai, les
observateurs sont notifiés, puis il repasse à faux (les observateurs sont de
nouveau notifiés). Tout cela dans le même cycle d'horloge (en réalité,
pendant le même appel de méthode). C'est la façon dont l'unité de jeu
informe les observateurs qu'il doivent commencer la simulation de la décharge.Mode graphique (GraphicMode)Compatibilité : Tous modèles.Réference: Apple IIe Technical Reference Manual
page 29 (PDF p63)Cette unité s'occupe du passage du mode texte aux modes graphiques,
excepté le mode double haute résolution qui a été implémenté plus tard.
L'Apple ][ a un mode texte et deux modes graphiques (basse et haute résolution).
Un mode mixte permet de partager l'écran en deux, en ayant 4 lignes de texte
en bas et le reste en graphique. Chaque mode possède deux pages correspondant
à deux espaces mémoire différents.InterrupteursInterrupteurOffOnTEXTMode graphiqueMode texteMIXEDMode plein écranMode mixtePAGE2Page 1 affichéePage 2 affichéeHIRESBasse résolution Haute résolutionAdressesAdresseNomAccèsEffet0x50TXTCLRRWPasse TEXT à 00x51TXTSETRWPasse TEXT à 10x52MIXCLRRWPasse MIXED à 00x53MIXSETRWPasse MIXED à 10x54TXTPAGE1RWPasse PAGE2 à 00x55TXTPAGE2RWPasse PAGE2 à 10x56LORESRWPasse HIRES à 00x57HIRESRWPasse HIRES à 1Et, sur le //e et les modèles suivants, quelques adresses de lectures ont été ajoutées :AdresseNomAccèsEffet0x1ARDTEXTR7Lit l'état de TEXT0x1BRDMIXEDR7Lit l'état de MIXED0x1CRDPAGE2R7Lit l'état de PAGE20x1DRDHIRESR7Lit l'état de HIRESPorts d'extension (Slots)Compatibilité : Tous modèles.Cette unité gère les ports d'extension de l'Apple. Elle ne fait que
transférer les requêtes de lectures et d'écriture sur l'espace $C090-$C0FF vers
l'unité d'entrée/sortie de la carte correspondante.Comme le Bus des ROM périphériques,
cette unité doit être informée quand une carte est insérée ou retirée.Méthodesvoid insert_card(int slot, CUnit *cardUnit);Indique à l'unité qu'une carte a été insérée. slot
est le numéro du port (1-7) et cardUnit est l'unité
d'E/S de la carte d'extension.void remove_card(int slot);Indique à l'unité qu'une carte a été retirée. slot
est le numéro du port (1-7).AdressesAdresseNomAccèsEffet0x90-0x9FRWTransféré aux adresses 0x00-0x0F de la carte du port 10xA0-0xAFRWTransféré aux adresses 0x00-0x0F de la carte du port 20xB0-0xBFRWTransféré aux adresses 0x00-0x0F de la carte du port 30xC0-0xCFRWTransféré aux adresses 0x00-0x0F de la carte du port 40xD0-0xDFRWTransféré aux adresses 0x00-0x0F de la carte du port 50xE0-0xEFRWTransféré aux adresses 0x00-0x0F de la carte du port 60xF0-0xFFRWTransféré aux adresses 0x00-0x0F de la carte du port 7Carte langage (Language Card)Compatibilité : Tous modèles (probablement sauf le ][).Réference : Apple IIe Technical Reference Manual
pages 79 à 83 (PDF pp113-117)Cette unité pilote le Bus de la carte
langage en utilisant trois interrupteurs : LCRAM, LCBNK2 et LCWRITE.Seuls LCRAM et LCBNK2 peuvent être lus depuis l'intérieur de l'Apple.
LCWRITE n'est pas le nom officiel pour cet interrupteur (j'ai choisis celui là car
je n'ai pas trouvé d'autre nom dans la documentation).Pour changer l'état de LCWRITE, deux requêtes de lectures doivent
être effectuées à l'adresse appropriée. Un quatrième interrupteur est utilisé
dans Vinace pour gérer cette double lecture. Il est appelé LCWCHG.InterrupteursInterrupteurOffOnLCBNK2Page 2 RAM utilisée en $D000-$DFFFPage 1 RAM utilisée en $D000-$DFFFLCRAMROM lue en $D000-$FFFFRAM lue en $D000-$DFFFLCWRITEPas d'écriture en $D000-$FFFFÉcriture en RAM en $D000-$FFFF (même si elle n'est pas visible)AdressesAdresseNomAccèsEffet0x11RDLCBNK2R7Lit l'état de LCBNK20x12RDLCRAMR7Lit l'état de LCRAM0x81RPasse LCBNK2 à 1, LCRAM à 1 et LCWRITE à 00x81RRPasse LCBNK2 à 1, LCRAM à 0 et LCWRITE à 10x82RPasse LCBNK2 à 1, LCRAM à 0 et LCWRITE à 00x83RRPasse LCBNK2 à 1, LCRAM à 1 et LCWRITE à 10x84-0x87Identique à 0x80-0x830x88RPasseLCBNK2 à 0, LCRAM à 1 et LCWRITE à 00x89RRPasse LCBNK2 à 0, LCRAM à 0 et LCWRITE à 10x8ARPasse LCBNK2 à 0, LCRAM à 0 et LCWRITE à 00x8BRRPasse LCBNK2 à 0, LCRAM à 1 et LCWRITE à 10x8C-0x8FIdentique à 0x88-0x8BMémoire auxiliaire (Aux Memory)Compatibilité: //e et suivants.Malheureusement cette unité n'est pas encore implémentée.Mode texte (Text Mode)Compatibilité: //e et suivants.Cette unité s'occupe du passage entre les modes 40 et 80 colonnes,
ainsi que du changement de police de caractère.InterrupteursInterrupteurOffOn80VIDAffichage 40 colonnesAffichage 80 colonnesALTCHARUtilisation de la police primaireUtilisation de la police alternativeAdressesAdresseNomAccèsEffet0x0CCLR80VIDWPasse 80VID à 00x0DSET80VIDWPasse 80VID à 10x0ECLRALTCHARWPasse ALTCHAR à 00x0FSETALTCHARWPasse ALTCHAR à 10x1ERDALTCHARR7Lit l'état de ALTCHAR0x1FRD80VIDR7Lit l'état de 80VIDRom E/S (I/O Rom)Compatibilité : //e, IIgsCertains modèles d'Apple avaient plus de 12Ko de ROM. Pour accéder
aux reste de la ROM, l'espace mémoire $C100-$CFFF, habituellement réservé
aux ROMs des périphériques, pouvait être utilisé. Une fenêtre en $C300-$C3FF,
correspondant à la carte 80 colonne, pouvait être sélectionnée spécifiquement.Cette unité pilote le Bus de la ROM E/S
qui s'occupe de la commutation entre la ROM interne et la ROM des périphériques
en $C100-$CFFF.InterrupteursInterrupteurOffOnCXROMROM périphériques en $C100-$CFFFROM interne en $C100-$CFFFC3ROMROM sélectionnée par CXROM en $C300-$C3FFROM interne en $C300-$C3FFAdressesAdresseNomAccèsEffet0x06SETSLOTCXROMWPasse CXROM à 00x07SETINTCXROMWPasse CXROM à 10x0ASETINTC3ROMWPasse C3ROM à 00x0BSETSLOTC3ROMWPasse C3ROM à 10x15RDCXROMR7Lit l'état de CXROM0x17RDC3ROMR7Lit l'état de C3ROMPas encore implémentéVoici des fonctionnalités qui doivent être implémentées :Entrée et sortie cassette128Ko de mémoire (AuxMemory)Signal d'effacement verticalLecture des images disques en format "ordre ProDOS" (.po) et en format "nibbles" (.nib)Écriture sur disquettesD'autres fonctionnalités peuvent aussi être implémentées mais elle sont moins importantes :Un clavier capable de faire du "coller"Un lecteur de disquette faisant du bruitRéférencesSur internetAsimovLe dépôt Asimov est le site internet où il faut
aller pour trouver des trucs sur l'Apple II. Il y a des images disque, la documentation
originale, des images des ROM, des émulateurs, etc.Le dépôt Asimov est ici :
ftp://ftp.apple.asimov.net/pub/apple_IIJon Relay's Apple II Info ArchivesJon Relay's Apple II Info Archives contient des trucs très utiles que
l'on peut aussi trouver dans les manuels de référence, excepté la fabuleuse
page sur la mémoire d'entrée sortie qui résume les entrées/sorties de tous
les modèles d'Apple II en un seul grand tableau :http://www.kreativekorp.com/miscpages/a2info/iomemory.shtmlLivres anglaisVoici les livres les plus intéressants. Ils peuvent tous être trouvés dans
le dépôt Asimov.Apple IIe Technical Reference ManualC'est la bible. Pratiquement tout y est expliqué. Je possède la version
française. La version originale anglaise se trouve ici :
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/Apple%20IIe%20Technical%20Reference%20Manual.pdfApple II Reference Manual January 1978C'est une bible plus ancienne. Aussi connu sous le nom du livre rouge.
Par chance, j'en ai récupéré un exemplaire sur ebay. Une version PDF se trouve ici :
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/Apple_II_Redbook.pdfUnderstanding the Apple IIJ'ai lu le chapitre 8, à propos du Disk II Controller car les manuels
Apple ne fournissaient aucune information à son propos. Je n'ai pas lu le
reste du livre (n'ayant pas de version papier) mais il semble vraiment
intéressant, allant en profondeur dans la description de l'Apple II. Une
version PDF se trouve ici :
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/understanding the apple ii.pdfEmulateurs existantsYAE - Yet Another Apple EmulatorAvant que je ne décide d'écrire Vinace, j'ai utilisé YAE. Il a beaucoup
de limitation : pas de joystick simple, pas d'interface facile pour les disquettes.J'ai tout d'abord essayé de l'améliorer mais j'ai rapidement réalisé
que réécrire un nouvel émulateur ne serait pas plus compliqué.J'ai beaucoup étudié le code source de YAE pendant l'écriture de
Vinace. J'ai récupéré les routines pour l'encodage et le décodage des nibbles,
utilisées dans les lecteurs de disquettes. Les fichiers
gcr.h et gcr.cpp
sont quasiment identiques à ceus dans YAE.Il semble que le site de YAE n'existe plus
(http://quark.netfront.net:6502/)
mais le code source peut toujours être trouvé sur le dépôt Asimov ici :
ftp://ftp.apple.asimov.net/pub/apple_II/emulators/yae/yae-0.1.tar.gzAppleblossom - Portable Open-Source Apple IIe EmulatorQuand je ne trouvais pas les réponses ni dans la documentation
ni dans le code source de YAE, je cherchais dans le source de Apple Blossom.J'ai pris le code pour la police de caractère depuis Apple Blossom.
Il est maintenant dans le fichier CCharset.cpp.Le code source de Apple Blossom est ici :
ftp://ftp.apple.asimov.net/pub/apple_II/emulators/appleblossom/appleblossom.zip