mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 00:37:27 +00:00
Add privilege and instruction error exceptions; permit two operands to be stored.
This commit is contained in:
parent
84c165459f
commit
334e3ec529
@ -155,19 +155,16 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
|
||||
#endif
|
||||
|
||||
// To limit tests run to a subset of files and/or of tests, uncomment and fill in below.
|
||||
_fileSet = [NSSet setWithArray:@[@"eor_and_or.json"]];
|
||||
_fileSet = [NSSet setWithArray:@[
|
||||
@"eor_and_or.json",
|
||||
|
||||
// Below this line are passing tests.
|
||||
@"abcd_sbcd.json",
|
||||
@"nbcd.json",
|
||||
@"ext.json"]];
|
||||
// _testSet = [NSSet setWithArray:@[@"CHK 41a8"]];
|
||||
}
|
||||
|
||||
//
|
||||
// Temporary notes on 68000 mk2:
|
||||
//
|
||||
// Passing so far:
|
||||
//
|
||||
// abcd_sbcd
|
||||
// nbcd
|
||||
// ext
|
||||
|
||||
- (void)testAll {
|
||||
// Get the full list of available test files.
|
||||
NSBundle *const bundle = [NSBundle bundleForClass:[self class]];
|
||||
|
@ -31,6 +31,7 @@ enum ExecutionState: int {
|
||||
FetchOperand_l,
|
||||
|
||||
StoreOperand,
|
||||
StoreOperand_bw,
|
||||
StoreOperand_l,
|
||||
|
||||
StandardException,
|
||||
@ -300,7 +301,27 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
instruction_ = decoder_.decode(opcode_);
|
||||
instruction_address_.l = program_counter_.l - 4;
|
||||
|
||||
// TODO: check for privilege and unrecognised instructions.
|
||||
// Check for a privilege violation.
|
||||
if(instruction_.requires_supervisor() && !status_.is_supervisor) {
|
||||
exception_vector_ = InstructionSet::M68k::Exception::PrivilegeViolation;
|
||||
MoveToState(StandardException);
|
||||
}
|
||||
|
||||
// Check for an unrecognised opcode.
|
||||
if(instruction_.operation == InstructionSet::M68k::Operation::Undefined) {
|
||||
switch(opcode_ & 0xf000) {
|
||||
default:
|
||||
exception_vector_ = InstructionSet::M68k::Exception::IllegalInstruction;
|
||||
continue;
|
||||
case 0xa000:
|
||||
exception_vector_ = InstructionSet::M68k::Exception::Line1010;
|
||||
continue;
|
||||
case 0xf000:
|
||||
exception_vector_ = InstructionSet::M68k::Exception::Line1111;
|
||||
continue;
|
||||
}
|
||||
MoveToState(StandardException);
|
||||
}
|
||||
|
||||
// Signal the bus handler if requested.
|
||||
if constexpr (signal_will_perform) {
|
||||
@ -766,42 +787,72 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
Prefetch(); // np
|
||||
MoveToNextOperand(FetchOperand_l);
|
||||
|
||||
#undef MoveToNextOperand
|
||||
|
||||
// MARK: - Store.
|
||||
|
||||
#define MoveToNextOperand(x) \
|
||||
++next_operand_; \
|
||||
if(next_operand_ == 2) { \
|
||||
MoveToState(Decode); \
|
||||
} \
|
||||
MoveToState(x)
|
||||
|
||||
// Store operand is a lot simpler: only one operand is ever stored, and its address
|
||||
// is already known. So this can either skip straight back to ::Decode if the target
|
||||
// is a register, otherwise a single write operation can occur.
|
||||
BeginState(StoreOperand):
|
||||
switch(instruction_.operand_size()) {
|
||||
case InstructionSet::M68k::DataSize::LongWord:
|
||||
SetupDataAccess(0, Microcycle::SelectWord);
|
||||
MoveToState(StoreOperand_l);
|
||||
|
||||
case InstructionSet::M68k::DataSize::Word:
|
||||
SetupDataAccess(0, Microcycle::SelectWord);
|
||||
MoveToState(StoreOperand_bw);
|
||||
|
||||
case InstructionSet::M68k::DataSize::Byte:
|
||||
SetupDataAccess(0, Microcycle::SelectByte);
|
||||
MoveToState(StoreOperand_bw);
|
||||
}
|
||||
|
||||
BeginState(StoreOperand_bw):
|
||||
if(!(operand_flags_ & 0x4 << next_operand_)) {
|
||||
MoveToNextOperand(StoreOperand_bw);
|
||||
}
|
||||
|
||||
if(instruction_.mode(next_operand_) <= Mode::AddressRegisterDirect) {
|
||||
registers_[instruction_.lreg(next_operand_)] = operand_[next_operand_];
|
||||
MoveToState(Decode);
|
||||
MoveToNextOperand(StoreOperand_bw);
|
||||
}
|
||||
|
||||
if(instruction_.operand_size() == InstructionSet::M68k::DataSize::LongWord) {
|
||||
MoveToState(StoreOperand_l);
|
||||
}
|
||||
|
||||
SetupDataAccess(
|
||||
0,
|
||||
(instruction_.operand_size() == InstructionSet::M68k::DataSize::Byte) ? Microcycle::SelectByte : Microcycle::SelectWord);
|
||||
SetDataAddress(effective_address_[next_operand_]);
|
||||
Access(operand_[next_operand_].low); // nw
|
||||
MoveToState(Decode);
|
||||
MoveToNextOperand(StoreOperand_bw);
|
||||
|
||||
BeginState(StoreOperand_l):
|
||||
if(!(operand_flags_ & 0x4 << next_operand_)) {
|
||||
MoveToNextOperand(StoreOperand_l);
|
||||
}
|
||||
|
||||
if(instruction_.mode(next_operand_) <= Mode::AddressRegisterDirect) {
|
||||
registers_[instruction_.lreg(next_operand_)] = operand_[next_operand_];
|
||||
MoveToNextOperand(StoreOperand_l);
|
||||
}
|
||||
|
||||
SetupDataAccess(0, Microcycle::SelectWord);
|
||||
SetDataAddress(effective_address_[next_operand_]);
|
||||
Access(operand_[next_operand_].low); // nw
|
||||
|
||||
effective_address_[next_operand_] -= 2;
|
||||
Access(operand_[next_operand_].high); // nW
|
||||
MoveToState(Decode);
|
||||
MoveToNextOperand(StoreOperand_l);
|
||||
|
||||
//
|
||||
// Various generic forms of perform.
|
||||
//
|
||||
#define MoveToWritePhase() \
|
||||
next_operand_ = operand_flags_ >> 3; \
|
||||
next_operand_ = 0; \
|
||||
if(operand_flags_ & 0x0c) MoveToState(StoreOperand) else MoveToState(Decode)
|
||||
|
||||
BeginState(Perform_np):
|
||||
|
Loading…
x
Reference in New Issue
Block a user