mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 15:32:04 +00:00
Merge pull request #35 from TomHarte/BRKDiversion
Adds a small amount of test coverage to the functioning of 6502 interrupts
This commit is contained in:
commit
7f10616be9
@ -69,7 +69,7 @@ void MOS6560::set_output_mode(OutputMode output_mode)
|
||||
chrominances = ntsc_chrominances;
|
||||
display_type = Outputs::CRT::NTSC60;
|
||||
_timing.cycles_per_line = 65;
|
||||
_timing.line_counter_increment_offset = 65 - 36; // TODO: 36 is from memory; need to look up.
|
||||
_timing.line_counter_increment_offset = 65 - 33; // TODO: this is a bit of a hack; separate vertical and horizontal counting
|
||||
_timing.lines_per_progressive_field = 261;
|
||||
_timing.supports_interlacing = true;
|
||||
break;
|
||||
|
@ -28,7 +28,6 @@ Machine::Machine() :
|
||||
_is_pal_region(false)
|
||||
{
|
||||
memset(_collisions, 0xff, sizeof(_collisions));
|
||||
set_reset_line(true);
|
||||
setup_reported_collisions();
|
||||
|
||||
for(int vbextend = 0; vbextend < 2; vbextend++)
|
||||
@ -414,8 +413,6 @@ void Machine::output_pixels(unsigned int count)
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
|
||||
{
|
||||
set_reset_line(false);
|
||||
|
||||
uint8_t returnValue = 0xff;
|
||||
unsigned int cycles_run_for = 3;
|
||||
|
||||
|
@ -55,7 +55,6 @@ Machine::Machine() :
|
||||
memset(_roms[c], 0xff, 16384);
|
||||
|
||||
_tape.set_delegate(this);
|
||||
set_reset_line(true);
|
||||
}
|
||||
|
||||
void Machine::setup_output(float aspect_ratio)
|
||||
@ -86,7 +85,6 @@ void Machine::close_output()
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
|
||||
{
|
||||
unsigned int cycles = 1;
|
||||
set_reset_line(false);
|
||||
|
||||
if(address < 0x8000)
|
||||
{
|
||||
|
@ -18,7 +18,6 @@ Machine::Machine() :
|
||||
_userPortVIA.set_delegate(this);
|
||||
_keyboardVIA.set_delegate(this);
|
||||
_tape.set_delegate(this);
|
||||
set_reset_line(true);
|
||||
}
|
||||
|
||||
Machine::~Machine()
|
||||
@ -28,8 +27,6 @@ Machine::~Machine()
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
|
||||
{
|
||||
set_reset_line(false);
|
||||
|
||||
// test for PC at F92F
|
||||
if(_use_fast_tape_hack && address == 0xf92f && operation == CPU6502::BusOperation::ReadOpcode)
|
||||
{
|
||||
|
@ -35,7 +35,7 @@
|
||||
4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73C7191D036BD90074D992 /* Vic20Document.swift */; };
|
||||
4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; };
|
||||
4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF01D03B517004291C3 /* Vic20.cpp */; };
|
||||
4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* TimingTests.swift */; };
|
||||
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; };
|
||||
4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; };
|
||||
4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; };
|
||||
4BB298F01B587D8400A49093 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BB297E31B587D8300A49093 /* TestMachine.mm */; };
|
||||
@ -323,6 +323,7 @@
|
||||
4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */; };
|
||||
4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; };
|
||||
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; };
|
||||
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */; };
|
||||
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -397,7 +398,7 @@
|
||||
4B73C71C1D036C030074D992 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Vic20Document.xib"; sourceTree = SOURCE_ROOT; };
|
||||
4B886FF01D03B517004291C3 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vic20.cpp; path = "Vic-20/Vic20.cpp"; sourceTree = "<group>"; };
|
||||
4B886FF11D03B517004291C3 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Vic20.hpp; path = "Vic-20/Vic20.hpp"; sourceTree = "<group>"; };
|
||||
4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = "<group>"; };
|
||||
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = "<group>"; };
|
||||
4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4BB297E01B587D8300A49093 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = "<group>"; };
|
||||
4BB297E11B587D8300A49093 /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = AllSuiteA.bin; sourceTree = "<group>"; };
|
||||
@ -708,6 +709,7 @@
|
||||
4BC9DF441D044FCA00F44158 /* ROMImages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ROMImages; path = ../../../../ROMImages; sourceTree = "<group>"; };
|
||||
4BC9DF4D1D04691600F44158 /* 6560.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6560.cpp; sourceTree = "<group>"; };
|
||||
4BC9DF4E1D04691600F44158 /* 6560.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6560.hpp; sourceTree = "<group>"; };
|
||||
4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502InterruptTests.swift; sourceTree = "<group>"; };
|
||||
4BCA98C21D065CA20062F44C /* 6522.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6522.hpp; sourceTree = "<group>"; };
|
||||
4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = "<group>"; };
|
||||
4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = "<group>"; };
|
||||
@ -1253,9 +1255,10 @@
|
||||
4B1E85801D176468001EF87D /* 6532Tests.swift */,
|
||||
4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */,
|
||||
4B1414611B58888700E04248 /* KlausDormannTests.swift */,
|
||||
4B92EAC91B7C112B00246143 /* TimingTests.swift */,
|
||||
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */,
|
||||
4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */,
|
||||
4B1414631B588A1100E04248 /* Test Binaries */,
|
||||
4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */,
|
||||
);
|
||||
path = "Clock SignalTests";
|
||||
sourceTree = "<group>";
|
||||
@ -1814,7 +1817,8 @@
|
||||
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */,
|
||||
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */,
|
||||
4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */,
|
||||
4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */,
|
||||
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */,
|
||||
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */,
|
||||
4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */,
|
||||
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */,
|
||||
4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */,
|
||||
|
73
OSBindings/Mac/Clock SignalTests/6502InterruptTests.swift
Normal file
73
OSBindings/Mac/Clock SignalTests/6502InterruptTests.swift
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// 6502InterruptTests.swift
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 28/06/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class MOS6502InterruptTests: XCTestCase {
|
||||
|
||||
var machine: CSTestMachine! = nil
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
// create a machine full of NOPs
|
||||
machine = CSTestMachine()
|
||||
for c in 0...65535 {
|
||||
machine.setValue(0xea, forAddress: UInt16(c))
|
||||
}
|
||||
|
||||
// set the IRQ vector to be 0x1234
|
||||
machine.setValue(0x34, forAddress: 0xfffe)
|
||||
machine.setValue(0x12, forAddress: 0xffff)
|
||||
|
||||
// add a CLI
|
||||
machine.setValue(0x58, forAddress: 0x4000)
|
||||
|
||||
// pick things off at 0x4000
|
||||
machine.setValue(0x4000, forRegister: CSTestMachineRegister.ProgramCounter)
|
||||
}
|
||||
|
||||
func testIRQLine() {
|
||||
// run for six cycles; check that no interrupt has occurred
|
||||
machine.runForNumberOfCycles(6)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4003, "No interrupt should have occurred with line low")
|
||||
|
||||
// enable the interrupt line, check that it was too late
|
||||
machine.irqLine = true
|
||||
machine.runForNumberOfCycles(2)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4004, "No interrupt should have occurred from interrupt raised between instructions")
|
||||
|
||||
// run for a further 7 cycles, confirm that the IRQ vector was jumped to
|
||||
machine.runForNumberOfCycles(7)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun")
|
||||
}
|
||||
|
||||
func testIFlagSet() {
|
||||
// enable the interrupt line, run for eleven cycles to get past the CLIP and the following NOP and into the interrupt routine
|
||||
machine.irqLine = true
|
||||
machine.runForNumberOfCycles(11)
|
||||
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun")
|
||||
XCTAssert(machine.valueForRegister(.Flags) & 0x04 == 0x04, "Interrupt status flag should be set")
|
||||
}
|
||||
|
||||
func testCLISEIFlagClear() {
|
||||
// set up an SEI as the second instruction, enable the IRQ line
|
||||
machine.setValue(0x78, forAddress: 0x4001)
|
||||
machine.irqLine = true
|
||||
|
||||
// run for four cycles; the CLI and SEI should have been performed
|
||||
machine.runForNumberOfCycles(4)
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x4002, "CLI/SEI pair should have been performed in their entirety")
|
||||
|
||||
// run for seven more cycles
|
||||
machine.runForNumberOfCycles(7)
|
||||
|
||||
// interrupt should have taken place despite SEI
|
||||
XCTAssert(machine.valueForRegister(.ProgramCounter) == 0x1234, "Interrupt routine should just have begun")
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
class TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
|
||||
private var endTime: UInt32 = 0
|
||||
|
@ -46,12 +46,8 @@ class KlausDormannTests: XCTestCase {
|
||||
|
||||
if newPC == oldPC {
|
||||
let error = errorForTrapAddress(oldPC)
|
||||
|
||||
if let error = error {
|
||||
NSException(name: "Failed test", reason: error, userInfo: nil).raise()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
XCTAssert(error == nil, "Failed with error \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,5 +41,7 @@ extern const uint8_t CSTestMachineJamOpcode;
|
||||
@property (nonatomic, readonly) BOOL isJammed;
|
||||
@property (nonatomic, readonly) uint32_t timestamp;
|
||||
@property (nonatomic, weak) id <CSTestMachineJamHandler> jamHandler;
|
||||
@property (nonatomic, assign) BOOL irqLine;
|
||||
@property (nonatomic, assign) BOOL nmiLine;
|
||||
|
||||
@end
|
||||
|
@ -99,4 +99,14 @@ class MachineJamHandler: public CPU6502::AllRAMProcessor::JamHandler {
|
||||
return _processor.get_timestamp();
|
||||
}
|
||||
|
||||
- (void)setIrqLine:(BOOL)irqLine {
|
||||
_irqLine = irqLine;
|
||||
_processor.set_irq_line(irqLine);
|
||||
}
|
||||
|
||||
- (void)setNmiLine:(BOOL)nmiLine {
|
||||
_nmiLine = nmiLine;
|
||||
_processor.set_nmi_line(nmiLine);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -92,9 +92,14 @@ template <class T> class Processor {
|
||||
enum MicroOp {
|
||||
CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH,
|
||||
CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand,
|
||||
CycleSetIReadBRKLow, CycleReadBRKHigh,
|
||||
OperationSetI,
|
||||
|
||||
OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector,
|
||||
CycleReadVectorLow, CycleReadVectorHigh,
|
||||
|
||||
CycleReadFromS, CycleReadFromPC,
|
||||
CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA,
|
||||
CycleNoWritePush,
|
||||
CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL,
|
||||
CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute,
|
||||
OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow,
|
||||
@ -121,7 +126,6 @@ template <class T> class Processor {
|
||||
OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSetOperandFromFlags,
|
||||
OperationSetFlagsFromA,
|
||||
CycleReadRSTLow, CycleReadRSTHigh, CycleReadNMILow, CycleReadNMIHigh,
|
||||
CycleScheduleJam
|
||||
};
|
||||
|
||||
@ -271,7 +275,7 @@ template <class T> class Processor {
|
||||
|
||||
static const MicroOp operations[256][10] = {
|
||||
|
||||
/* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, CycleSetIReadBRKLow, CycleReadBRKHigh),
|
||||
/* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationBRKPickVector, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, OperationSetI, CycleReadVectorLow, CycleReadVectorHigh),
|
||||
/* 0x01 ORA x, ind */ IndexedIndirectRead(OperationORA),
|
||||
/* 0x02 JAM */ JAM, /* 0x03 ASO x, ind */ IndexedIndirectReadModifyWrite(OperationASO),
|
||||
/* 0x04 NOP zpg */ ZeroNop(), /* 0x05 ORA zpg */ ZeroRead(OperationORA),
|
||||
@ -455,11 +459,19 @@ template <class T> class Processor {
|
||||
|
||||
int _cycles_left_to_run;
|
||||
|
||||
bool _ready_line_is_enabled;
|
||||
bool _reset_line_is_enabled;
|
||||
bool _irq_line_is_enabled, _irq_request_history[2];
|
||||
bool _nmi_line_is_enabled;
|
||||
enum InterruptRequestFlags: uint8_t {
|
||||
Reset = 0x80,
|
||||
IRQ = 0x40,
|
||||
NMI = 0x20,
|
||||
|
||||
PowerOn = 0x10,
|
||||
};
|
||||
uint8_t _interrupt_requests;
|
||||
|
||||
bool _ready_is_active;
|
||||
bool _ready_line_is_enabled;
|
||||
|
||||
bool _irq_line_is_enabled, _irq_request_history;
|
||||
|
||||
/*!
|
||||
Gets the program representing an RST response.
|
||||
@ -470,11 +482,12 @@ template <class T> class Processor {
|
||||
static const MicroOp reset[] = {
|
||||
CycleFetchOperand,
|
||||
CycleFetchOperand,
|
||||
CyclePullOperand,
|
||||
CyclePullOperand,
|
||||
CyclePullOperand,
|
||||
CycleReadRSTLow,
|
||||
CycleReadRSTHigh,
|
||||
CycleNoWritePush,
|
||||
CycleNoWritePush,
|
||||
OperationRSTPickVector,
|
||||
CycleNoWritePush,
|
||||
CycleReadVectorLow,
|
||||
CycleReadVectorHigh,
|
||||
OperationMoveToNextProgram
|
||||
};
|
||||
return reset;
|
||||
@ -487,12 +500,16 @@ template <class T> class Processor {
|
||||
*/
|
||||
inline const MicroOp *get_irq_program() {
|
||||
static const MicroOp reset[] = {
|
||||
CycleFetchOperand,
|
||||
CycleFetchOperand,
|
||||
CyclePushPCH,
|
||||
CyclePushPCL,
|
||||
OperationBRKPickVector,
|
||||
OperationSetOperandFromFlags,
|
||||
CyclePushOperand,
|
||||
CycleSetIReadBRKLow,
|
||||
CycleReadBRKHigh,
|
||||
OperationSetI,
|
||||
CycleReadVectorLow,
|
||||
CycleReadVectorHigh,
|
||||
OperationMoveToNextProgram
|
||||
};
|
||||
return reset;
|
||||
@ -505,12 +522,15 @@ template <class T> class Processor {
|
||||
*/
|
||||
inline const MicroOp *get_nmi_program() {
|
||||
static const MicroOp reset[] = {
|
||||
CycleFetchOperand,
|
||||
CycleFetchOperand,
|
||||
CyclePushPCH,
|
||||
CyclePushPCL,
|
||||
OperationNMIPickVector,
|
||||
OperationSetOperandFromFlags,
|
||||
CyclePushOperand,
|
||||
CycleReadNMILow,
|
||||
CycleReadNMIHigh,
|
||||
CycleReadVectorLow,
|
||||
CycleReadVectorHigh,
|
||||
OperationMoveToNextProgram
|
||||
};
|
||||
return reset;
|
||||
@ -528,8 +548,8 @@ template <class T> class Processor {
|
||||
_scheduledPrograms{nullptr, nullptr, nullptr, nullptr},
|
||||
_interruptFlag(Flag::Interrupt),
|
||||
_s(0),
|
||||
_nextBusOperation(BusOperation::None)
|
||||
|
||||
_nextBusOperation(BusOperation::None),
|
||||
_interrupt_requests(InterruptRequestFlags::PowerOn)
|
||||
{
|
||||
// only the interrupt flag is defined upon reset but get_flags isn't going to
|
||||
// mask the other flags so we need to do that, at least
|
||||
@ -576,13 +596,16 @@ template <class T> class Processor {
|
||||
#define checkSchedule(op) \
|
||||
if(!_scheduledPrograms[scheduleProgramsReadPointer]) {\
|
||||
scheduleProgramsReadPointer = _scheduleProgramsWritePointer = scheduleProgramProgramCounter = 0;\
|
||||
if(_reset_line_is_enabled) {\
|
||||
schedule_program(get_reset_program());\
|
||||
} else if(_nmi_line_is_enabled) {\
|
||||
_nmi_line_is_enabled = false;\
|
||||
schedule_program(get_nmi_program());\
|
||||
} else if(_irq_request_history[0]) {\
|
||||
schedule_program(get_irq_program());\
|
||||
if(_interrupt_requests) {\
|
||||
if(_interrupt_requests & (InterruptRequestFlags::Reset | InterruptRequestFlags::PowerOn)) {\
|
||||
_interrupt_requests &= ~InterruptRequestFlags::PowerOn;\
|
||||
schedule_program(get_reset_program());\
|
||||
} else if(_interrupt_requests & InterruptRequestFlags::NMI) {\
|
||||
_interrupt_requests &= ~InterruptRequestFlags::NMI;\
|
||||
schedule_program(get_nmi_program());\
|
||||
} else if(_interrupt_requests & InterruptRequestFlags::IRQ) {\
|
||||
schedule_program(get_irq_program());\
|
||||
} \
|
||||
} else {\
|
||||
schedule_program(fetch_decode_execute);\
|
||||
}\
|
||||
@ -602,8 +625,8 @@ template <class T> class Processor {
|
||||
while (!_ready_is_active && number_of_cycles > 0) {
|
||||
|
||||
if(nextBusOperation != BusOperation::None) {
|
||||
_irq_request_history[0] = _irq_request_history[1];
|
||||
_irq_request_history[1] = _irq_line_is_enabled && !_interruptFlag;
|
||||
_interrupt_requests = (_interrupt_requests & ~InterruptRequestFlags::IRQ) | (_irq_request_history ? InterruptRequestFlags::IRQ : 0);
|
||||
_irq_request_history = _irq_line_is_enabled && !_interruptFlag;
|
||||
number_of_cycles -= static_cast<T *>(this)->perform_bus_operation(nextBusOperation, busAddress, busValue);
|
||||
nextBusOperation = BusOperation::None;
|
||||
}
|
||||
@ -665,18 +688,28 @@ template <class T> class Processor {
|
||||
case CyclePushPCL: push(_pc.bytes.low); break;
|
||||
case CyclePushOperand: push(_operand); break;
|
||||
case CyclePushA: push(_a); break;
|
||||
case CycleNoWritePush:
|
||||
{
|
||||
uint16_t targetAddress = _s | 0x100; _s--;
|
||||
read_mem(_operand, targetAddress);
|
||||
}
|
||||
break;
|
||||
|
||||
#undef push
|
||||
|
||||
case CycleReadFromS: throwaway_read(_s | 0x100); break;
|
||||
case CycleReadFromPC: throwaway_read(_pc.full); break;
|
||||
|
||||
case CycleReadNMILow: read_mem(_pc.bytes.low, 0xfffa); break;
|
||||
case CycleReadNMIHigh: read_mem(_pc.bytes.high, 0xfffb); break;
|
||||
case CycleReadRSTLow: read_mem(_pc.bytes.low, 0xfffc); break;
|
||||
case CycleReadRSTHigh: read_mem(_pc.bytes.high, 0xfffd); break;
|
||||
case CycleSetIReadBRKLow: _interruptFlag = Flag::Interrupt; read_mem(_pc.bytes.low, 0xfffe); break;
|
||||
case CycleReadBRKHigh: read_mem(_pc.bytes.high, 0xffff); break;
|
||||
case OperationBRKPickVector:
|
||||
// NMI can usurp BRK-vector operations
|
||||
nextAddress.full = (_interrupt_requests & InterruptRequestFlags::NMI) ? 0xfffa : 0xfffe;
|
||||
_interrupt_requests &= ~InterruptRequestFlags::NMI; // TODO: this probably doesn't happen now?
|
||||
break;
|
||||
case OperationNMIPickVector: nextAddress.full = 0xfffa; break;
|
||||
case OperationRSTPickVector: nextAddress.full = 0xfffc; break;
|
||||
case CycleReadVectorLow: read_mem(_pc.bytes.low, nextAddress.full); break;
|
||||
case CycleReadVectorHigh: read_mem(_pc.bytes.high, nextAddress.full+1); break;
|
||||
case OperationSetI: _interruptFlag = Flag::Interrupt; break;
|
||||
|
||||
case CyclePullPCL: _s++; read_mem(_pc.bytes.low, _s | 0x100); break;
|
||||
case CyclePullPCH: _s++; read_mem(_pc.bytes.high, _s | 0x100); break;
|
||||
@ -1171,7 +1204,7 @@ template <class T> class Processor {
|
||||
*/
|
||||
inline void set_reset_line(bool active)
|
||||
{
|
||||
_reset_line_is_enabled = active;
|
||||
_interrupt_requests = (_interrupt_requests & ~InterruptRequestFlags::Reset) | (active ? InterruptRequestFlags::Reset : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1181,7 +1214,16 @@ template <class T> class Processor {
|
||||
*/
|
||||
inline bool get_reset_line()
|
||||
{
|
||||
return _reset_line_is_enabled;
|
||||
return !!(_interrupt_requests & InterruptRequestFlags::Reset);
|
||||
}
|
||||
|
||||
/*!
|
||||
This emulation automatically sets itself up in power-on state at creation, which has the effect of triggering a
|
||||
reset at the first opportunity. Use @c set_power_on to disable that behaviour.
|
||||
*/
|
||||
inline void set_power_on(bool active)
|
||||
{
|
||||
_interrupt_requests = (_interrupt_requests & ~InterruptRequestFlags::PowerOn) | (active ? InterruptRequestFlags::PowerOn : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1202,7 +1244,7 @@ template <class T> class Processor {
|
||||
inline void set_nmi_line(bool active)
|
||||
{
|
||||
// NMI is edge triggered, not level
|
||||
_nmi_line_is_enabled |= active;
|
||||
_interrupt_requests |= (active ? InterruptRequestFlags::NMI : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -12,7 +12,10 @@
|
||||
|
||||
using namespace CPU6502;
|
||||
|
||||
AllRAMProcessor::AllRAMProcessor() : _timestamp(0) {}
|
||||
AllRAMProcessor::AllRAMProcessor() : _timestamp(0)
|
||||
{
|
||||
set_power_on(false);
|
||||
}
|
||||
|
||||
int AllRAMProcessor::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user