Skip to content

Commit 7823542

Browse files
committed
add proper reading and writing of registers in 6809 TFR and EXG instructions
1 parent fd82936 commit 7823542

File tree

1 file changed

+160
-59
lines changed

1 file changed

+160
-59
lines changed

mc6809.c

Lines changed: 160 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
167282
int 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

Comments
 (0)