L'émulation DCMOTO to7-70 est différente du matériel réel

Couvre tous les domaines de l'émulation ou de la virtualisation ainsi que les discussions sur les divers outils associés.

Modérateurs : Papy.G, fneck, Carl

wietze
Messages : 15
Inscription : 18 juil. 2021 10:56

L'émulation DCMOTO to7-70 est différente du matériel réel

Message par wietze »

Salut les gars,

J'ai enfin pu utiliser le code que j'ai fait en utilisant l'émulateur DCMOTO (émulateur génial, merci Daniel) sur le vrai matériel car j'ai enfin reçu le sddrive (encore une fois, merci Daniel !).

J'ai découvert un comportement sur l'émulateur qui n'est pas similaire à la vraie machine et cela concerne le comportement du timer. J'ai trouvé du code reproductible pour tester à la fois sur le matériel réel et sur l'émulateur (to7-70) et je peux confirmer dans mon cas que le comportement est différent.

Le cas est le suivant :
- J'utilise mon propre code de vecteur d'interruption, dans lequel je change la fréquence du timer dans le temps ; voici mon code de vecteur d'interruption :

Code : Tout sélectionner

; le vecteur d'interruption réel
intr
	dec .waiter ; intervalle pour changer le timer
	bne .ok
		lda #255
		sta .waiter
		ldd .myfreq ; charger la fréquence actuelle
		subd #50 ; rendre plus rapide
		std .myfreq
.smc		
		std TMRCP
.ok

.intrc
	ldb $E7C3 ; si vous gardez ceci, mais désactivez la ligne 74, l'émulateur fonctionne, mais pas le matériel.

	lda $E7C1 ; poke le soundcbip
	eora #8
	sta $E7C1
; lda TMRCP ; effacer le contrôleur de temporisation
	rti
.waiter dc.b 255
.myfreq dc.w 2499
L'exemple ci-dessus de la minuterie d'interruption changerait la tonalité désirée (augmentation du son de la tonalité au fil du temps) sur l'émulateur. Mais il ne produit que du bruit sur la vraie machine. Si l'on décommente également la ligne $E7C3, le comportement sur l'émulateur et le matériel réel sont les mêmes.

Si on `décompose' ensuite `lda TMRCP', cela fonctionne sur le vrai matériel. De cet exemple, je déduis que l'utilisation du registre $E7C3 sur l'émulateur a un effet secondaire lié au registre TMRCP, qui n'est pas présent sur le matériel réel.

Ci-joint vous trouverez un fichier zip avec quelques trucs :
- code source complet de l'exemple ci-dessus (assemblé avec vasm6809)
- 3 binaires (fd/sd) que l'on peut tester sur le matériel réel et sur l'émulateur pour vérifier s'ils se comportent de la même manière ; mais vous pouvez tout aussi bien changer le code source ou créer l'exemple vous-même.

J'espère que vous pourrez comprendre pourquoi l'émulateur se comporte différemment.

Bien à vous,
Wietze

p.s. J'espère que ce qui précède est clair, je peux fournir une vidéo du comportement réel du matériel si vous le souhaitez.
Pièces jointes
example.zip
(95.63 Kio) Téléchargé 63 fois
Daniel
Messages : 15449
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: L'émulation DCMOTO to7-70 est différente du matériel réel

Message par Daniel »

Une erreur est probable dans l'émulation du 6846. C'est un circuit complexe et son émulation est difficile.
Voici le code utilisé par dcmoto. Si vous trouvez une anomalie, n'hésitez pas à la signaler.

Code : Tout sélectionner

/*---------------------------------------------------------------------------*\
|  DC6846EMUL.C - Motorola 6846 timer emulation                               |
|  Author    : Daniel Coulom - danielcoulom@gmail.com                         |
|  Web site  : http://dcmoto.free.fr                                          |
|-----------------------------------------------------------------------------|
|                                                                             |
|  This file is part of Thomson emulators by Daniel Coulom.                   |
|                                                                             |
|  These emulators are free software : you can redistribute them and/or       |
|  modify them under the terms of the GNU General Public License as           |
|  published by the Free Software Foundation, either version 3 of the         |
|  License, or (at your option) any later version.                            |
|                                                                             |
|  These emulators are distributed in the hope that they will be useful,      |
|  but WITHOUT ANY WARRANTY; without even the implied warranty of             |
|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU           |
|  General Public License for more details.                                   |
|                                                                             |
|  You should have received a copy of the GNU General Public License          |
|  along with the emulator. If not, see <http://www.gnu.org/licenses/>.       |
|                                                                             |
|-----------------------------------------------------------------------------|
|                     Version juillet 2014                                    |
|                     Modifiee en avril 2020                                  |
\*---------------------------------------------------------------------------*/


/*
// Registres du 6846 //////////////////////////////////////////////////////////

E7C0= registre d'etat composite port C (CSR)
- csr0= cp0 timer interrupt flag
- csr1= cp1 interrupt flag (TO8: en entree, reception clavier)
- csr2= cp2 interrupt flag (TO8: en sortie, signal MUTE)
- csr3-csr6 unused and set to zeroes
- csr7= composite interrupt flag (si au moins un interrupt flag à 1)

E7C1= registre de controle peripherique port C (PCR) (PCRC)
- pcr0= CP1 interruption mask (0=masked, 1=enabled)
- pcr1= CP1 active edge (0=descendant, 1=montant)
- pcr2= CP1 input latch (0=not latched, 1=latched on active CP1)
- pcr3= beep
- pcr4=
- pcr5= CP2 direction (0=input, 1=output)
- pcr6=
- pcr7= reset (0=normal operation, 1=reset CSR1, CSR2 and periph data)

E7C2= registre de direction de donnees port C (DDR) (DDRC)
- ddr0-ddr7= peripheral data line 0-7 direction (0=input, 1=output)

E7C3= registre de donnees peripheriques port C (PRC) (PDR)
- p0-out: commutation page video (0=couleur 1=forme) emule par le gate array
- p1-in : interrupteur du crayon optique (0=ouvert 1=ferme)
- p2-out: commutation ROM (0=cartouche 1=interne)
- p3    : inutilise (ancienne commande led clavier du 707 et TO7/70)
- p4-out: commutation banque systeme (0=banque0 1=banque1)
- p5-out: acknowledge de reception d'un code touche (0=acknowledge 1=attente)
- p6_in : signal busy de l'imprimante (0=occupee 1=disponible)
- p7-in : entree magnetophone (0=deconnecte ou signal, 1=connecte sans signal)

E7C4= registre d'etat composite (CSR)
      les adresses 0 et 4 pointent sur le même registre

E7C5= registre controle temporisateur (TCR)
- tcr0: internal reset (0=timer enabled, 1=reset state)
- tcr1: clock source (0=external clock, 1=internal clock)
- tcr2: x8 prescale enable (0=clock not prescale 1=prescale x8)
- tcr3: mode compteur bit0
- tcr4: mode compteur bit1
- tcr5: mode compteur bit2
- tcr6: interrupt enable (0=IRQ masked, 1= IRQ enabled)
- tcr7: timer output enable (0=output disabled (low), 1=output enabled)

E7C6= registre temporisateur octet de poids fort (TMSB)

E7C7= registre temporisateur octet de poids faible (TLSB)

Reset du flag interruption timer csr0 :
1) Timer Reset - Internal Reset Bit TCR0=1 or External Reset=0
2) Any Counter Initialization condition
3) A Write Timer Latches command if Time Interval modes (TCR3=1) are being used.
4) A Read Timer Counter command, provided this is preceded by a Read Composite
   Status Register while CSR0 is set. This latter condition prevents missing
   an Interrupt Request generated after reading the Status Register and prior
   to reading the counter.

*/

//registres du 6846
#define CSR  port[0]  //Composite Status Register
#define PCR  port[1]  //Peripheral Control Register
#define DDR  port[2]  //Data Direction Register
#define PR   port[3]  //input/output port
#define TCR  port[5]  //Timer Control Register
#define TMSB port[6]  //Timer MSB latch(en ecriture) ou compteur(en lecture)
#define TLSB port[7]  //Timer LSB latch(en ecriture) ou compteur(en lecture)

int timer6846;          //compteur du timer 6846 * 8
int latch6846;          //registre latch du timer 6846 * 8
int latchbuffer;        //buffer pour l'octet de poids fort du latch
int readcsr0;           //flag indiquant la lecture du CSR du 6846 avec CSR0=1
int readcsr1;           //flag indiquant la lecture du CSR du 6846 avec CSR1=1
int readcsr2;           //flag indiquant la lecture du CSR du 6846 avec CSR2=1

extern char port[];     //ports d'entrees/sorties
extern int dc6809_irq;  //IRQ 6809

// Reset 6846 /////////////////////////////////////////////////////////////////
void Reset6846()
{
 CSR = 0x00; //the combination status register is cleared of all interrupt flags
 PCR = 0x80; //peripheral control register is cleared except for bit 7 (/RESET)
 DDR = 0x00; //data direction register is cleared
 PR  = 0x00; //peripheral data register is cleared
 TCR = 0x01; //timer control register are reset to 0 except for bit 0.
 latch6846 = 65535 * 8; //the counter latches are preset to their maximal count
 timer6846 = 0;         //the counter output is cleared
 dc6809_irq = 0;        //pas d'irq
}

// Update 6846 CSR7 ///////////////////////////////////////////////////////////
void Update6846csr7()
{
//CSR0 = timer interrupt flag
//CSR1 = CP1 interrupt flag
//CSR2 = CP2 interrupt flag
//CSR3-CSR6 not used (zero)
//CSR7 = composite interrupt flag
 int csr7;
 CSR &= 0x07;
 csr7 = 0;
 if(CSR & 0x01) if(TCR & 0x40) csr7 = 1;
 if(CSR & 0x02) if(PCR & 0x01) csr7 = 1;
 if(CSR & 0x04) if(PCR & 0x08) csr7 = 1;
 if(csr7) CSR |= 0x80; //set CSR7
 dc6809_irq = 0;      //clear IRQ flag
 dc6809_irq |= csr7;  //set IRQ flag
 readcsr0 = readcsr1 = readcsr2 = 0;
}

// Counter initialisation /////////////////////////////////////////////////////
void Init6846counter()
{
//Counter Initialization is defined as the transfer of data from the latches
//to the counter with attendant clearing of the Individual Interrupt Flag
//associated with the counter.
 timer6846 = latch6846; //reinitialisation du compteur du timer

 //The Timer Interrupt Flag (CSR0) is cleared
 //by any Counter Initialization Condition
 CSR &= 0xfe;           //clear timer interrupt flag
 Update6846csr7();      //set composite interrupt flag
}

// Read CSR (Composite Status Register) ///////////////////////////////////////
int Read6846csr()
{
 //The remaining bits of the Composite Status Register (CSR3-CSR6)
 //are unused. Thet return a logic zero when read.
 CSR &= 0x87;

 //MC6846 Interrupt Flags are cleared by either reading or writing to the
 //Peripheral Data Register - provided that this sequence is followed :
 //a) Flag set
 //b) Read Composite Status Register
 //c) Read/Write Peripheral Data Register

 //Flags pour "Read Composite Status Register while CSR0,1,2 is set".
 readcsr0 = (CSR & 1) ? 1 : 0; //indicateur de lecture CSR avec CSR0=1
 readcsr1 = (CSR & 2) ? 1 : 0; //indicateur de lecture CSR avec CSR1=1
 readcsr2 = (CSR & 4) ? 1 : 0; //indicateur de lecture CSR avec CSR2=1
 return CSR;
}

// Set 6846 CSR1 Interrupt Flag ///////////////////////////////////////////////
void Set6846csr1()
{
 //Peripheral input line CP1 is an input-only that sets the Interrupt Flags
 //of the Composite Status Register. The active transition for this signal
 //is programmed by the peripheral control register of the parallel port.
 //CP1 may also act as a strobe for the peripheral data register when it is
 //used as an input latch.

 //Pour simplifier, avec le TO8, l'appel de cette fonction positionne le
 //flag d'interruption CSR1 si PCR0=1 (et rien d'autre).
 if((PCR & 1) == 0) return;  //CP1 interrupt masked
 CSR |=2;                    //set CP1 interrupt flag
 Update6846csr7();           //set composite interrupt flag
}

// Update timer counter ///////////////////////////////////////////////////////
void Update6846counter(int opcycles)
{
 if((TCR & 1) == 1) return; //preset mode, pas de comptage
 if((TCR & 2) == 0) return; //external clock selected (CTC connecte a la masse)
 if((TCR & 4) == 0) timer6846 -= opcycles << 3;  //pas de prescaler
 if((TCR & 4) == 4) timer6846 -= opcycles;       //prescaler multiplie par 8
 if(timer6846 > 0) return;  //le compteur n'est pas encore a zero

 //Fin du comptage : le compteur est negatif ou nul
 //Counter recycling or reinitialization occurs when a clock input
 //is recognized after the counter has reached an all-zero state.
 //In this case, data is transferred from the Latches to the Counter,
 //but the Interrupt Flag is unaffected.
 timer6846 += latch6846; //reset counter
 CSR |= 0x01;      //set timer interrupt flag
 Update6846csr7(); //set composite interrupt flag

 //instructions supprimees le 02/04/2020 suite a l'amelioration de l'emulation
 //reste a verifier pour Las-Vegas
 //CSR &= 0xfd;      //clear keyboard interrupt flag (evite pb Las-Vegas) ????
 //if(TCR & 0x40)    //TCR6 = 1 (interrupt enabled)
 //{
 // CSR |= 0x80;     //set composite interrupt flag
 // dc6809_irq |= 1; //set 6809 IRQ
 //}
}

// Read timer counter /////////////////////////////////////////////////////////
int Read6846counter(int byte)
{
 //The Timer Interrupt Flag (CSR0) is cleared by a Read Timer Counter command,
 //provided this is preceded by a Read Composite Status Register while CSR0
 //is set. This latter condition prevent missing an Interrupt Request generated
 //after reading the Status Register and prior to reading the counter.

 if(readcsr0)       //Il y a eu un read CSR avec CSR0=1 (timer interrupt)
 {
  CSR &= 0xfe;      //clear timer interrupt flag
  Update6846csr7(); //set composite interrupt flag
 }
 //byte : 0=LSB, 1=MSB
 return (byte) ? (timer6846 >> 11) & 0xff : (timer6846 >> 3) & 0xff;
}

// Read 6846 port /////////////////////////////////////////////////////////////
int Read6846port()
{
 //MC6846 Interrupt Flags are cleared by either reading or writing to the
 //Peripheral Data Register - provided that this sequence is followed :
 //a) Flag set
 //b) Read Composite Status Register
 //c) Read/Write Peripheral Data Register
 if(readcsr0) CSR &= 0xfe;
 if(readcsr1) CSR &= 0xfd;
 if(readcsr2) CSR &= 0xfb;
 Update6846csr7();

 //retour des donnees
 return PR & DDR;
}

// Write PCR (Peripheral Control Register) ////////////////////////////////////
void Write6846pcr(int c)
{
 //Bit 7 of the Peripheral Control Register (PCR7) may be used to initialize
 //the peripheral section of the MC6846. When this bit is set high, the
 //peripheral data register, the peripheral data direction register, and
 //the interrupt flags associated with the peripheral port (CSR1 and CSR2)
 //are all cleared. Other bits in the peripheral control register are not
 //affected by PCR7.
 //PCR7 is set by either a logic zero at the External /RESET interrupt or
 //under program control by writing a "one" into the location. In any case,
 //PCR7 may be cleared only by writing a "zero" into the location while /RESET
 //is high. The bit must be cleared to activate the port.
 PCR = c;
 if(PCR & 0x80)     //si PCR7 est positionne
 {
  PR  = 0;          //peripheral data register is cleared
  DDR = 0;          //data direction register is cleared
  CSR &= 0x01;      //CSR1 and CSR2 are cleared
  Update6846csr7(); //set composite interrupt flag
 }
}

// Write DDR (Data Direction Register) ////////////////////////////////////////
void Write6846ddr(int c)
{
 //It is necessary to set up the Peripheral Control Register first, since
 //PCR7 = "0" is a condition for writing data into the Data Direction Register
 //(A logic zero at the external /RESET input automatically set PCR7).
 if(PCR & 0x80) return;  //si PCR7 est positionne ne rien faire
 DDR = c;
}

// Write 6846 port ////////////////////////////////////////////////////////////
void Write6846port(int c)
{
 //It is necessary to set up the Peripheral Control Register first, since
 //PCR7 = "0" is a condition for writing data into the Data Direction Register
 //(A logic zero at the external /RESET input automatically set PCR7).
 if(PCR & 0x80) return;  //si PCR7 est positionne ne rien faire
 PR = c;

 //MC6846 Interrupt Flags are cleared by either reading or writing to the
 //Peripheral Data Register - provided that this sequence is followed :
 //a) Flag set
 //b) Read Composite Status Register
 //c) Read/Write Peripheral Data Register
 if(readcsr0) CSR &= 0xfe;
 if(readcsr1) CSR &= 0xfd;
 if(readcsr2) CSR &= 0xfb;
 Update6846csr7();
}

// Write TCR (Timer Control Register) /////////////////////////////////////////
void Write6846tcr(int c)
{
 TCR = c;   //0x46=continuous mode  pour TO7/70
 //The least significant bit of the Control Register is used as an internal
 //reset bit. When this bit is a logic zero, all timers are allowed to operate
 //in the modes prescribed by the remaining bits of the timer control register.
 //Writing "one" into Timer Control Register B0 (TCR0) causes the counter to
 //be preset with the contents of the counter latches, all counter clocks are
 //disabled, and the timer output and interrupt flag (Status Register) are reset.
 if(TCR & 0x01) Init6846counter(); //reinitialisation du timer

 //Timer Control Register Bit 1 (TCR1) is used to select the clock source.
 //When TCR1="0" the external clock input /CTC is selected, and when TCR1="1",
 //the timer uses E.

 //Timer Control Register Bit2 (TCR2) enables the divide-by-8 prescaler (TCR2="1").
 //In this mode, the clock frequency is divided by eight before being applied to
 //the counter. When TCR2="0" the system clock is applied directly to the counter.

 //TCR3, 4, 5 select the Timer Operating Mode.

 //Timer Control Register Bit 6 (TCR6) is used to mask or enable the Timer
 //Interrupt Request. When TCR6="0", the Interrupt Flag is masked from the timer.
 //When TCR6="1", the Interrupt Flag is enabled into bit 7 of the Composite
 //Status Register (Composite IRQ Bit), which appears on the /IRQ output pin.
 Update6846csr7();         //calcul composite interrupt flag

 //ancienne programmation a supprimer
 //if(TCR & 0x40) {CSR |= 0x80; dc6809_irq = 1;}
 //          else {CSR &= 0x7f; dc6809_irq = 0;}

 //Timer Control Register Bit 7 (TCR7) has a special function when the timer
 //is in the Cascaded Single Shot mode. In all other modes, TCR7 merely act
 //as an output enable bit. If TCR7 = "0", the Counter Timer Output (CTO) is
 //forced low. Writing a logic one into TCR7 enables CTO. (Ecriture LEP)
}

// Write timer latch //////////////////////////////////////////////////////////
void Write6846latch(int byte, int value)
//byte: 0=low byte(LSB), 1=high byte(MSB)
//Data from the MSB Buffer will automatically be transferred into the Most
//Significant Byte of the counter latches simultaneously with the transfer of
//the Data Bus information to the Least Significant Byte of the Counter Latch.
{
 value &= 0xff;  //valeur a multiplier par 8 pour initialiser le latch

 //Most Significant Byte
 if(byte) {latchbuffer = value << 11; return;} //stockage latch MSB

 //Least Significant Byte = Write Timer Latches
 latch6846 = latchbuffer + (value << 3);       //transfert dans latch
 //latch6846 += 18;                            //petit decalage (trop grand)
 latch6846 += 8;                               //petit decalage (16/03/2021)

 //The Timer Interrupt Flag (CSR0) is cleared by a Write Timer Latches command
 //if Time Interval modes (TCR3="1") are being used.
 if(TCR & 0x08)
 {
  CSR &= 0xfe;      //clear timer interrupt flag
  Update6846csr7(); //set composite interrupt flag
 }

 //A Write Timer Latches command can be selected
 //as a Counter Initialization signal by clearing TCR4
 if((TCR & 0x10) == 0) Init6846counter();        //counter initialization

}
Daniel
L'obstacle augmente mon ardeur.
Fool-DupleX
Messages : 1638
Inscription : 06 avr. 2009 12:07

Re: L'émulation DCMOTO to7-70 est différente du matériel réel

Message par Fool-DupleX »

Rappelons également que le circuit a été réimplémenté par Thomson sur les TO8/8D/9+ et que le comportement de cette nouvelle version n'est pas tout à fait identique en termes de cycles au circuit Motorola d'origine.
__sam__
Messages : 6799
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: L'émulation DCMOTO to7-70 est différente du matériel réel

Message par __sam__ »

Le changement de fréquence dans le buzzer est un exercice pas facile. Je l'ai mis en oeuvre dans la démo HNY2013 (le son est joué au buzzer par le timer).

Le code source est dispo dans le fichier SAP. C'est pas le plus sympa à extraire, aussi voici un zip avec tous mes code ASM expérimentaux de l'époque (plusieurs mois avant que la démo ne soit prête). En relisant les commentaires (tstson.ass) je suis tombé sur ceci:

Code : Tout sélectionner

SndIntr	set	*
* le moniteur du TO8 force b3=0 en
* $E7C1 a chaque fois que $60DC
* tombe a zero (il est decremente
* a chaque interruption). On lui
* donne donc une valeur != 1.
* Ici a l'entree de l'interrupt
* A contient $6019 qui ne peut
* être nul.
	sta	$60DC	* un truc!=1
Ca peut éventuellement expliquer que tu entendes du bruit sur machine réelle.
Pièces jointes
asm_hny2013.zip
(41.87 Kio) Téléchargé 59 fois
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 15449
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: L'émulation DCMOTO to7-70 est différente du matériel réel

Message par Daniel »

J'ai testé le fichier border.sd avec les vraies machines.
- Avec le TO7/70 en BASIC 1.0 il produit des sons parasites
- Avec le TO8 en BASIC 1.0 ou en BASIC 128 il ne produit aucun son

Avec l'émulateur dcmoto, en mode TO7/70 ou TO8, border.sd produit un son. La fréquence augmente progressivement.
Il y a donc une différence de comportement avec l'émulateur, mais je n'ai pas encore trouvé la cause.

Le fichier tco-off produit des parasites avec dcmoto et avec le vrai TO7/70. Il est silencieux avec le TO8.

Le fichier tco-on fonctionne aussi bien avec dcmoto, avec le vrai TO7/70 et avec le vrai TO8.
Daniel
L'obstacle augmente mon ardeur.
wietze
Messages : 15
Inscription : 18 juil. 2021 10:56

Re: L'émulation DCMOTO to7-70 est différente du matériel réel

Message par wietze »

Aplogies Daniel,

J'aurais pu être plus clair sur ce point, et je suppose que cela confirme vos conclusions :

Pour les fichiers liés au code source :
- tco_on.fd : a `lda TMRCP', mais pas `ldb $e7c3', est le fonctionnement correct du timer (je présume) ; et produit des sons clairs à la fois sur l'émulateur et le matériel

- border.fd : a `ldb $e7c3' mais pas `lda TMRCP ' ; produit des tonalités claires sur l'émulateur, pas sur le matériel

- tco_off.fd : n'a pas de `ldb $e7c3' et pas de `lda TMRCP', et ne produit PAS de sons clairs sur l'un ou l'autre des appareils

J'ai regardé le code source .c, mais je cherche la source complète du DCMOTO parce que je ne vois pas où les fonctions sont appelées. Mon intuition est que l'accès à $e7c3 déclenche toujours une mise à jour du compteur (est-ce le latch ?).

Salutations,
Wietze
Daniel
Messages : 15449
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: L'émulation DCMOTO to7-70 est différente du matériel réel

Message par Daniel »

Voici les appels des fonctions du 6846 en émulation du TO7/70 :

1) En écriture

Code : Tout sélectionner

// Ecriture port entree/sortie TO7 ///////////////////////////////////////////
void TO7writeport(int a, int c)
{
 extern int lepmotor;
 extern int mea8000;

 a &= 0x3f;
 switch(a)
 {
  //------------------6846 port I/O et timer ----------------------------------
  case 0x00: //CSR = registre d'etat composite port (read only)
             break;
  case 0x01: //PCRC = registre de controle peripherique port C
             Write6846pcr(c);
             beep = (c & 8) << 3;
             break;
  case 0x02: //DDRC = registre de direction de donnees port C
             Write6846ddr(c);
             break;
  case 0x03: //PRC = registre de donnees peripheriques port C
             Write6846port(c);
             Setcapslock((c & 0x08) ? 0 : 1);
             TO7videobank(); //selection page video et couleur cadre
             break;
  case 0x04: //CSR = registre d'etat composite (idem 0x00)
             break;
  case 0x05: //TCR = registre de controle du temporisateur
             Write6846tcr(c);
             break;
  case 0x06: //TMSB = registre temporisateur octet de poids fort
             Write6846latch(1, c);
             break;
  case 0x07: //TLSB = registre temporisateur octet de poids faible
             Write6846latch(0, c);
             break;
  //----------------------------------------------------------------------------

2) En lecture

Code : Tout sélectionner

// Lecture port entree/sortie TO7 ////////////////////////////////////////////
int TO7readport(int a)
{
 int r;
 extern int tapedrive, lightpen, lbutton;
 extern int joysposition, joysaction;
 extern int leplevel, lepmotor;
 extern int mea8000;
 extern int capslock;

 a &= 0x3f;
 r = port[a];
 switch(a)
 {
  //------------------6846 port I/O et timer ----------------------------------
  case 0x00: r = Read6846csr(); break;                //6846 CSR
  case 0x01: r = port[a]; break;                      //6846 PCR
  case 0x02: r = port[a]; break;                      //6846 DDR
  case 0x03: r = Read6846port();                      //6846 PORT
             r |= (lightpen&&lbutton) << 1;           //interrupteur crayon
             if(tapedrive) if(lepmotor) leplevel = 1; //pour detection du LEP
             if(leplevel) r |= 0x80; else r &= 0x7f;  //signal en sortie du lep
             if(capslock) r &= 0xf7; else r |= 0x08;  //signal capslock
             break;
  case 0x04: r = Read6846csr(); break;                //6846 CSR
  case 0x06: r = Read6846counter(1); break;           //6846 counter MSB
  case 0x07: r = Read6846counter(0); break;           //6846 counter LSB

L'accès à $E7C3 en lecture [int Read6846port()] ou en écriture [void Write6846port(int c)] ne met pas à jour le compteur.
La différence entre l'émulateur et le vrai TO7/70 peut venir d'un petit décalage du déclenchement de l'interruption timer.
Daniel
L'obstacle augmente mon ardeur.
Répondre