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:
commit
211a6e5114
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user