1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-19 23:29:05 +00:00

Merge pull request #1166 from TomHarte/6502Exhaustive

This commit is contained in:
Thomas Harte 2023-09-10 17:02:20 -04:00 committed by GitHub
commit 211a6e5114
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 38 deletions

View File

@ -236,7 +236,7 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
case Instruction::Relative: { case Instruction::Relative: {
std::size_t operand_address = address_mapper(address); std::size_t operand_address = address_mapper(address);
if(operand_address >= memory.size()) return; if(operand_address >= memory.size()) return;
address++; ++address;
instruction.operand = memory[operand_address]; instruction.operand = memory[operand_address];
} }
@ -291,20 +291,34 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
} }
// Decide on overall flow control. // Decide on overall flow control.
if(instruction.operation == Instruction::RTS || instruction.operation == Instruction::RTI) return;
if(instruction.operation == Instruction::BRK) return; // TODO: check whether IRQ vector is within memory range // All relative instructions are flow control.
if(instruction.operation == Instruction::JSR) {
disassembly.remaining_entry_points.push_back(instruction.operand);
}
if(instruction.operation == Instruction::JMP) {
if(instruction.addressing_mode == Instruction::Absolute)
disassembly.remaining_entry_points.push_back(instruction.operand);
return;
}
if(instruction.addressing_mode == Instruction::Relative) { if(instruction.addressing_mode == Instruction::Relative) {
uint16_t destination = uint16_t(address + int8_t(instruction.operand)); uint16_t destination = uint16_t(address + int8_t(instruction.operand));
disassembly.remaining_entry_points.push_back(destination); disassembly.remaining_entry_points.push_back(destination);
} }
switch(instruction.operation) {
default: break;
case Instruction::KIL:
case Instruction::RTS:
case Instruction::RTI:
case Instruction::BRK: // TODO: check whether IRQ vector is within memory range.
disassembly.implicit_entry_points.push_back(address);
return;
case Instruction::JMP:
// Adding a new entry point for relative jumps was handled above.
if(instruction.addressing_mode == Instruction::Absolute) {
disassembly.remaining_entry_points.push_back(instruction.operand);
}
return;
case Instruction::JSR:
disassembly.remaining_entry_points.push_back(instruction.operand);
break;
}
} }
} }

View File

@ -14,7 +14,7 @@ namespace Analyser::Static::Disassembly {
template <typename D, typename S> struct PartialDisassembly { template <typename D, typename S> struct PartialDisassembly {
D disassembly; D disassembly;
std::vector<S> remaining_entry_points; std::vector<S> remaining_entry_points;
std::map<S, S> touched; // Maps from start of range to end. std::vector<S> implicit_entry_points;
}; };
template <typename D, typename S, typename Disassembler> D Disassemble( template <typename D, typename S, typename Disassembler> D Disassemble(
@ -50,18 +50,15 @@ template <typename D, typename S, typename Disassembler> D Disassemble(
break; break;
} }
// Otherwise, find the first area between or just beyond a disassembled range // Otherwise, copy in the new 'implicit entry points' (i.e. all locations that are one after
// that isn't yet disassembled and chuck it onto the list. // a disassembled region). There's a test above that'll ignore any which have already been
for(const auto &pair: partial_disassembly.touched) { // disassembled from.
const auto end = pair.second; std::move(
if(partial_disassembly.touched.find(end) == partial_disassembly.touched.end()) { partial_disassembly.implicit_entry_points.begin(),
if(address_mapper(end) < memory.size()) { partial_disassembly.implicit_entry_points.end(),
partial_disassembly.remaining_entry_points.push_back(end); std::back_inserter(partial_disassembly.remaining_entry_points)
} );
partial_disassembly.implicit_entry_points.clear();
break;
}
}
} }
return partial_disassembly.disassembly; return partial_disassembly.disassembly;

View File

@ -546,9 +546,6 @@ struct Z80Disassembler {
disassembly.disassembly.internal_calls.insert(entry_point); disassembly.disassembly.internal_calls.insert(entry_point);
Accessor accessor(memory, address_mapper, entry_point); Accessor accessor(memory, address_mapper, entry_point);
auto &touched = disassembly.touched[entry_point];
touched = entry_point;
while(!accessor.at_end()) { while(!accessor.at_end()) {
Instruction instruction; Instruction instruction;
instruction.address = accessor.address(); instruction.address = accessor.address();
@ -561,9 +558,6 @@ struct Z80Disassembler {
// Store the instruction away. // Store the instruction away.
disassembly.disassembly.instructions_by_address[instruction.address] = instruction; disassembly.disassembly.instructions_by_address[instruction.address] = instruction;
// Apply all touches.
touched = accessor.address();
// Update access tables. // Update access tables.
int access_type = int access_type =
((instruction.source == Instruction::Location::Operand_Indirect) ? 1 : 0) | ((instruction.source == Instruction::Location::Operand_Indirect) ? 1 : 0) |
@ -595,7 +589,7 @@ struct Z80Disassembler {
break; break;
} }
// Add any (potentially) newly discovered entry point. // Add any (potentially) newly-discovered entry point.
if( instruction.operation == Instruction::Operation::JP || if( instruction.operation == Instruction::Operation::JP ||
instruction.operation == Instruction::Operation::JR || instruction.operation == Instruction::Operation::JR ||
instruction.operation == Instruction::Operation::CALL || instruction.operation == Instruction::Operation::CALL ||
@ -604,13 +598,19 @@ struct Z80Disassembler {
} }
// This is it if: an unconditional RET, RETI, RETN, JP or JR is found. // This is it if: an unconditional RET, RETI, RETN, JP or JR is found.
if(instruction.condition != Instruction::Condition::None) continue; switch(instruction.operation) {
default: break;
if(instruction.operation == Instruction::Operation::RET) return; case Instruction::Operation::RET:
if(instruction.operation == Instruction::Operation::RETI) return; case Instruction::Operation::RETI:
if(instruction.operation == Instruction::Operation::RETN) return; case Instruction::Operation::RETN:
if(instruction.operation == Instruction::Operation::JP) return; case Instruction::Operation::JP:
if(instruction.operation == Instruction::Operation::JR) return; case Instruction::Operation::JR:
if(instruction.condition == Instruction::Condition::None) {
disassembly.implicit_entry_points.push_back(accessor.address());
return;
}
}
} }
} }
}; };

View File

@ -115,7 +115,7 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
// be at play; disassemble to try to figure it out. // be at play; disassemble to try to figure it out.
std::vector<uint8_t> first_8k; std::vector<uint8_t> first_8k;
first_8k.insert(first_8k.begin(), segment.data.begin(), segment.data.begin() + 8192); first_8k.insert(first_8k.begin(), segment.data.begin(), segment.data.begin() + 8192);
Analyser::Static::Z80::Disassembly disassembly = const Analyser::Static::Z80::Disassembly disassembly =
Analyser::Static::Z80::Disassemble( Analyser::Static::Z80::Disassemble(
first_8k, first_8k,
Analyser::Static::Disassembler::OffsetMapper(start_address), Analyser::Static::Disassembler::OffsetMapper(start_address),