1
//============================================================================
3
// MM MM 6666 555555 0000 2222
4
// MMMM MMMM 66 66 55 00 00 22 22
5
// MM MMM MM 66 55 00 00 22
6
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
7
// MM MM 66 66 55 00 00 22
8
// MM MM 66 66 55 55 00 00 22
9
// MM MM 6666 5555 0000 222222
11
// Copyright (c) 1995-2010 by Bradford W. Mott, Stephen Anthony
12
// and the Stella Team
14
// See the file "License.txt" for information on usage and redistribution of
15
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
17
// $Id: M6502.cxx 2001 2010-04-10 21:37:23Z stephena $
18
//============================================================================
20
//#define DEBUG_OUTPUT
21
#define debugStream cout
23
#ifdef DEBUGGER_SUPPORT
24
#include "Debugger.hxx"
25
#include "Expression.hxx"
30
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
31
M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
32
: myExecutionStatus(0),
34
mySystemCyclesPerProcessorCycle(systemCyclesPerProcessorCycle),
35
myLastAccessWasRead(true),
36
myTotalInstructionCount(0),
37
myNumberOfDistinctAccesses(0),
42
#ifdef DEBUGGER_SUPPORT
48
myJustHitTrapFlag = false;
51
// Compute the System Cycle table
52
for(uInt32 t = 0; t < 256; ++t)
54
myInstructionSystemCycleTable[t] = ourInstructionCycleTable[t] *
55
mySystemCyclesPerProcessorCycle;
59
debugStream << "( Fm Ln Cyc Clk) ( P0 P1 M0 M1 BL) "
60
<< "flags A X Y SP Code Disasm" << endl
65
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68
#ifdef DEBUGGER_SUPPORT
70
myBreakCondNames.clear();
74
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
75
void M6502::install(System& system)
77
// Remember which system I'm installed in
81
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
84
// Clear the execution status flags
85
myExecutionStatus = 0;
87
// Set registers to default values
93
myLastAccessWasRead = true;
95
// Load PC from the reset vector
96
PC = (uInt16)mySystem->peek(0xfffc) | ((uInt16)mySystem->peek(0xfffd) << 8);
98
myTotalInstructionCount = 0;
101
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
104
myExecutionStatus |= MaskableInterruptBit;
107
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110
myExecutionStatus |= NonmaskableInterruptBit;
113
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
116
myExecutionStatus |= StopExecutionBit;
119
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
120
uInt8 M6502::PS() const
142
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143
void M6502::PS(uInt8 ps)
147
B = true; // B = ps & 0x10; The 6507's B flag always true
154
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
155
inline uInt8 M6502::peek(uInt16 address)
157
if(address != myLastAddress)
159
myNumberOfDistinctAccesses++;
160
myLastAddress = address;
162
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
164
#ifdef DEBUGGER_SUPPORT
165
if(myReadTraps != NULL && myReadTraps->isSet(address))
167
myJustHitTrapFlag = true;
168
myHitTrapInfo.message = "RTrap: ";
169
myHitTrapInfo.address = address;
173
uInt8 result = mySystem->peek(address);
174
myLastAccessWasRead = true;
175
myLastPeekAddress = address;
179
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
180
inline void M6502::poke(uInt16 address, uInt8 value)
182
if(address != myLastAddress)
184
myNumberOfDistinctAccesses++;
185
myLastAddress = address;
187
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
189
#ifdef DEBUGGER_SUPPORT
190
if(myWriteTraps != NULL && myWriteTraps->isSet(address))
192
myJustHitTrapFlag = true;
193
myHitTrapInfo.message = "WTrap: ";
194
myHitTrapInfo.address = address;
198
mySystem->poke(address, value);
199
myLastAccessWasRead = false;
200
myLastPokeAddress = address;
203
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
204
bool M6502::execute(uInt32 number)
206
// Clear all of the execution status bits except for the fatal error bit
207
myExecutionStatus &= FatalErrorBit;
209
// Loop until execution is stopped or a fatal error occurs
212
for(; !myExecutionStatus && (number != 0); --number)
214
#ifdef DEBUGGER_SUPPORT
215
if(myJustHitTrapFlag)
217
if(myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address))
219
myJustHitTrapFlag = false;
224
if(myBreakPoints != NULL)
226
if(myBreakPoints->isSet(PC))
228
if(myDebugger->start("BP: ", PC))
233
int cond = evalCondBreaks();
236
string buf = "CBP: " + myBreakCondNames[cond];
237
if(myDebugger->start(buf))
241
uInt16 operandAddress = 0;
244
// Reset the peek/poke address pointers
245
myLastPeekAddress = myLastPokeAddress = 0;
247
// Fetch instruction at the program counter
251
debugStream << ::hex << setw(2) << (int)A << " "
252
<< ::hex << setw(2) << (int)X << " "
253
<< ::hex << setw(2) << (int)Y << " "
254
<< ::hex << setw(2) << (int)SP << " "
255
<< setw(4) << (PC-1) << ": "
256
<< setw(2) << (int)IR << " "
257
// << "<" << ourAddressingModeTable[IR] << " ";
258
// debugStream << hex << setw(4) << operandAddress << " ";
259
<< setw(3) << ourInstructionMnemonicTable[IR]
261
// debugStream << "PS=" << ::hex << setw(2) << (int)PS() << " ";
263
// debugStream << "Cyc=" << dec << mySystem->cycles();
267
// Call code to execute the instruction
270
// 6502 instruction emulation is generated by an M4 macro file
274
// Oops, illegal instruction executed so set fatal error flag
275
myExecutionStatus |= FatalErrorBit;
278
myTotalInstructionCount++;
281
// See if we need to handle an interrupt
282
if((myExecutionStatus & MaskableInterruptBit) ||
283
(myExecutionStatus & NonmaskableInterruptBit))
285
// Yes, so handle the interrupt
289
// See if execution has been stopped
290
if(myExecutionStatus & StopExecutionBit)
292
// Yes, so answer that everything finished fine
296
// See if a fatal error has occured
297
if(myExecutionStatus & FatalErrorBit)
299
// Yes, so answer that something when wrong
303
// See if we've executed the specified number of instructions
306
// Yes, so answer that everything finished fine
312
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
313
void M6502::interruptHandler()
315
// Handle the interrupt
316
if((myExecutionStatus & MaskableInterruptBit) && !I)
318
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
319
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
320
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
321
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
324
PC = (uInt16)mySystem->peek(0xFFFE) | ((uInt16)mySystem->peek(0xFFFF) << 8);
326
else if(myExecutionStatus & NonmaskableInterruptBit)
328
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
329
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
330
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
331
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
333
PC = (uInt16)mySystem->peek(0xFFFA) | ((uInt16)mySystem->peek(0xFFFB) << 8);
336
// Clear the interrupt bits in myExecutionStatus
337
myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
340
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
341
bool M6502::save(Serializer& out) const
343
const string& CPU = name();
349
out.putByte((char)A); // Accumulator
350
out.putByte((char)X); // X index register
351
out.putByte((char)Y); // Y index register
352
out.putByte((char)SP); // Stack Pointer
353
out.putByte((char)IR); // Instruction register
354
out.putInt(PC); // Program Counter
356
out.putBool(N); // N flag for processor status register
357
out.putBool(V); // V flag for processor status register
358
out.putBool(B); // B flag for processor status register
359
out.putBool(D); // D flag for processor status register
360
out.putBool(I); // I flag for processor status register
361
out.putBool(notZ); // Z flag complement for processor status register
362
out.putBool(C); // C flag for processor status register
364
out.putByte((char)myExecutionStatus);
366
// Indicates the number of distinct memory accesses
367
out.putInt(myNumberOfDistinctAccesses);
368
// Indicates the last address which was accessed
369
out.putInt(myLastAddress);
372
catch(const char* msg)
374
cerr << "ERROR: M6502::save" << endl << " " << msg << endl;
381
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
382
bool M6502::load(Serializer& in)
384
const string& CPU = name();
388
if(in.getString() != CPU)
391
A = (uInt8) in.getByte(); // Accumulator
392
X = (uInt8) in.getByte(); // X index register
393
Y = (uInt8) in.getByte(); // Y index register
394
SP = (uInt8) in.getByte(); // Stack Pointer
395
IR = (uInt8) in.getByte(); // Instruction register
396
PC = (uInt16) in.getInt(); // Program Counter
398
N = in.getBool(); // N flag for processor status register
399
V = in.getBool(); // V flag for processor status register
400
B = in.getBool(); // B flag for processor status register
401
D = in.getBool(); // D flag for processor status register
402
I = in.getBool(); // I flag for processor status register
403
notZ = in.getBool(); // Z flag complement for processor status register
404
C = in.getBool(); // C flag for processor status register
406
myExecutionStatus = (uInt8) in.getByte();
408
// Indicates the number of distinct memory accesses
409
myNumberOfDistinctAccesses = (uInt32) in.getInt();
410
// Indicates the last address which was accessed
411
myLastAddress = (uInt16) in.getInt();
413
catch(const char* msg)
415
cerr << "ERROR: M6502::laod" << endl << " " << msg << endl;
423
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
424
ostream& operator<<(ostream& out, const M6502::AddressingMode& mode)
428
case M6502::Absolute:
431
case M6502::AbsoluteX:
434
case M6502::AbsoluteY:
440
case M6502::Immediate:
443
case M6502::Indirect:
446
case M6502::IndirectX:
449
case M6502::IndirectY:
455
case M6502::Relative:
472
#ifdef DEBUGGER_SUPPORT
473
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
474
void M6502::attach(Debugger& debugger)
476
// Remember the debugger for this microprocessor
477
myDebugger = &debugger;
480
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
481
unsigned int M6502::addCondBreak(Expression *e, const string& name)
483
myBreakConds.push_back(e);
484
myBreakCondNames.push_back(name);
485
return myBreakConds.size() - 1;
488
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
489
void M6502::delCondBreak(unsigned int brk)
491
if(brk < myBreakConds.size())
493
delete myBreakConds[brk];
494
myBreakConds.remove_at(brk);
495
myBreakCondNames.remove_at(brk);
499
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
500
void M6502::clearCondBreaks()
502
for(uInt32 i = 0; i < myBreakConds.size(); i++)
503
delete myBreakConds[i];
505
myBreakConds.clear();
506
myBreakCondNames.clear();
509
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
510
const StringList& M6502::getCondBreakNames() const
512
return myBreakCondNames;
515
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
516
int M6502::evalCondBreaks()
518
for(uInt32 i = 0; i < myBreakConds.size(); i++)
519
if(myBreakConds[i]->evaluate())
522
return -1; // no break hit
525
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
526
void M6502::setBreakPoints(PackedBitArray *bp)
531
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
532
void M6502::setTraps(PackedBitArray *read, PackedBitArray *write)
535
myWriteTraps = write;
540
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
541
uInt32 M6502::ourInstructionCycleTable[256] = {
542
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
543
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, // 0
544
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 1
545
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, // 2
546
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 3
547
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, // 4
548
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 5
549
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, // 6
550
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 7
551
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, // 8
552
2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, // 9
553
2, 6, 2, 6, 3, 3, 3, 4, 2, 2, 2, 2, 4, 4, 4, 4, // a
554
2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, // b
555
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, // c
556
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // d
557
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, // e
558
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 // f