@@ -163,6 +163,121 @@ void MC6809SetTraceTriggers(const std::vector<unsigned short>& triggers)
163163 CPUTraceTriggers = triggers ;
164164}
165165
166+
167+ // This function performs a read from a register index specified in a
168+ // TFR or EXG instruction. This function only returns the correct value
169+ // for EXG instructions when the first register in the exchange (MSN) is
170+ // an 8 bit register. The value is returned as a 16 bit value for all
171+ // registers based on the behavior of the 6809 CPU as follows:
172+ //
173+ // * All 16 bit registers return their respective values.
174+ // * ACCA and ACCB return their values with the MSB set to 0xFF.
175+ // * Condition Code (CC) and Data Pointer (DP) return their values in
176+ // both the MSG and LSB.
177+ // * Invalid register encodings return a constant value of 0xFFFF.
178+ //
179+ static uint16_t MC6809ReadTfrExgRegister (uint8_t reg )
180+ {
181+ uint16_t result ;
182+
183+ switch (reg & 0x0F )
184+ {
185+ case 0 : // D
186+ case 1 : // X
187+ case 2 : // Y
188+ case 3 : // U
189+ case 4 : // S
190+ case 5 : // PC
191+ result = * xfreg16 [reg ];
192+ break ;
193+
194+ case 8 : // A
195+ case 9 : // B
196+ result = 0xff00 | * ureg8 [reg & 7 ];
197+ break ;
198+
199+ case 10 : // CC
200+ case 11 : // DP
201+ result = ((uint16_t )* ureg8 [reg & 7 ]) << 8 | * ureg8 [reg & 7 ];
202+ break ;
203+
204+ default :
205+ result = 0xffff ;
206+ break ;
207+ }
208+
209+ return result ;
210+ }
211+
212+ // This function performs a read from a register index specified in an
213+ // EXG instruction when the first register in the exchange (MSN) is
214+ // a 16 bit register. The value is returned as a 16 bit value for all
215+ // registers based on the behavior of the 6809 CPU as follows:
216+ //
217+ // * All 16 bit registers return their respective values.
218+ // * All 8 bit registers return respective value with the MSB set to 0xFF.
219+ // * Invalid register encodings return a constant value of 0xFFFF.
220+ //
221+ static uint16_t MC6809ReadExgRegister (uint8_t reg )
222+ {
223+ uint16_t result ;
224+
225+ switch (reg & 0x0F )
226+ {
227+ case 0 : // D
228+ case 1 : // X
229+ case 2 : // Y
230+ case 3 : // U
231+ case 4 : // S
232+ case 5 : // PC
233+ result = * xfreg16 [reg ];
234+ break ;
235+
236+ case 8 : // A
237+ case 9 : // B
238+ case 10 : // CC
239+ case 11 : // DP
240+ result = 0xff00 | * ureg8 [reg & 7 ];
241+ break ;
242+
243+ default :
244+ result = 0xffff ;
245+ break ;
246+ }
247+
248+ return result ;
249+ }
250+
251+ // This function performs a write to a register index specified in a
252+ // TFR or EXG instruction.
253+ static void MC6809WriteTfrExgRegister (uint8_t reg , uint16_t value )
254+ {
255+ switch (reg & 0x0F )
256+ {
257+ case 0 : // D
258+ case 1 : // X
259+ case 2 : // Y
260+ case 3 : // U
261+ case 4 : // S
262+ case 5 : // PC
263+ * xfreg16 [reg ] = value ;
264+ break ;
265+
266+ case 8 : // A
267+ case 9 : // B
268+ case 10 : // CC
269+ case 11 : // DP
270+ * ureg8 [reg & 7 ] = value & 0xff ;
271+ break ;
272+
273+ default :
274+ // Invalid register encoding, do nothing
275+ break ;
276+ }
277+ }
278+
279+
280+
166281// Do instructions for CycleFor cycles. Return number cycles over.
167282int MC6809Exec (int CycleFor )
168283{
@@ -480,79 +595,65 @@ void Do_Opcode(int CycleFor)
480595 break ;
481596
482597 case EXG_M : //1E
483- postbyte = MemRead8 (pc .Reg ++ );
484- ccbits = getcc ();
485- if ( ((postbyte & 0x80 )>>4 )== (postbyte & 0x08 )) //Verify like size registers
598+ postbyte = MemRead8 (pc .Reg );
599+ ++ pc .Reg ;
486600 {
487- if (postbyte & 0x08 ) //8 bit EXG
601+ ccbits = getcc ();
602+
603+ // Get the indexes of the first and second registers.
604+ const unsigned char first_register = postbyte >> 4 ;
605+ const unsigned char second_register = postbyte & 0x0f ;
606+
607+ // Exchange differs if 16 bit register or 8 bit register is first
608+ uint16_t first_value ;
609+ uint16_t second_value ;
610+ if ((postbyte & 0x80 ) != 0 )
488611 {
489- temp8 = (* ureg8 [((postbyte & 0x70 ) >> 4 )]);
490- (* ureg8 [((postbyte & 0x70 ) >> 4 )]) = (* ureg8 [postbyte & 0x07 ]);
491- (* ureg8 [postbyte & 0x07 ])= temp8 ;
612+ // The first register is an 8 bit register which enables
613+ // TFR/EXG behavior when reading 8 bit registers.
614+ first_value = MC6809ReadTfrExgRegister (first_register );
615+ second_value = MC6809ReadTfrExgRegister (second_register );
492616 }
493- else // 16 bit EXG
617+ else
494618 {
495- uint16_t * src = xfreg16 [((postbyte & 0x70 ) >> 4 )];
496- uint16_t * dest = xfreg16 [postbyte & 0x07 ];
497- // todo: find out which program triggers it
498- assert (src );
499- assert (dest );
500- uint16_t srcValue = src ? * src : 0xFFFF ;
501- uint16_t destValue = dest ? * dest : 0xFFFF ;
502- if (src ) * src = destValue ;
503- if (dest ) * dest = srcValue ;
619+ // The first register is a 16 bit register which has unique
620+ // behavior when reading 8 bit registers.
621+ first_value = MC6809ReadExgRegister (first_register );
622+ second_value = MC6809ReadExgRegister (second_register );
504623 }
624+
625+ MC6809WriteTfrExgRegister (second_register , first_value );
626+ MC6809WriteTfrExgRegister (first_register , second_value );
627+
628+ setcc (ccbits );
505629 }
506- setcc ( ccbits );
630+
507631 CycleCounter += 8 ;
508632 break ;
509633
510634 case TFR_M : //1F
511- postbyte = MemRead8 (pc .Reg ++ );
512- Source = postbyte >>4 ;
513- Dest = postbyte & 15 ;
514- switch (Dest )
635+ postbyte = MemRead8 (pc .Reg );
636+ ++ pc .Reg ;
515637 {
516- case 0 :
517- case 1 :
518- case 2 :
519- case 3 :
520- case 4 :
521- case 5 :
522- case 6 :
523- case 7 :
524- * xfreg16 [Dest ]= 0xFFFF ;
525- if ((Source == 12 ) | (Source == 13 ))
526- {
527- * xfreg16 [Dest ] = 0 ;
528- }
529- else if (Source <= 7 )
530- {
531- //make sure the source is valud
532- if (xfreg16 [Source ])
533- {
534- * xfreg16 [Dest ] = * xfreg16 [Source ];
535- }
536- }
537- break ;
638+ Source = postbyte >> 4 ; // Source register
639+ Dest = postbyte & 15 ; // Destination register
640+
641+ // Refresh the CC register with the bits representation. This *MUST*
642+ // be done before reading the source register as the bits are changed
643+ // without updating the CC register itself.
644+ ccbits = getcc ();
645+
646+ // Move the register value from the source to the destination.
647+ const uint16_t value = MC6809ReadTfrExgRegister (Source );
648+ MC6809WriteTfrExgRegister (Dest , value );
649+
650+ // Update the CC register bits representation.
651+ setcc (ccbits );
538652
539- case 8 :
540- case 9 :
541- case 10 :
542- case 11 :
543- case 14 :
544- case 15 :
545- ccbits = getcc ();
546- * ureg8 [Dest & 7 ]= 0xFF ;
547- if ( (Source == 12 ) | (Source == 13 ) )
548- * ureg8 [Dest & 7 ]= 0 ;
549- else
550- if (Source > 7 )
551- * ureg8 [Dest & 7 ]= * ureg8 [Source & 7 ];
552- setcc (ccbits );
553653 break ;
554654 }
555- CycleCounter += 6 ;
655+
656+ CycleCounter += 6 ;
556657 break ;
557658
558659 case BRA_R : //20
0 commit comments