mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Merge pull request #100 from TomHarte/SuperChipDetection
Adds detection and emulation of the Super Chip
This commit is contained in:
commit
997707a45b
@ -87,8 +87,21 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
}
|
||||
|
||||
// check for a ROM read
|
||||
if((address&0x1000) && isReadOperation(operation)) {
|
||||
returnValue &= rom_pages_[(address >> 10)&3][address&1023];
|
||||
uint16_t masked_address = address & 0x1fff;
|
||||
if(address&0x1000)
|
||||
{
|
||||
if(isReadOperation(operation) && (!uses_superchip_ || masked_address > 0x10ff)) {
|
||||
returnValue &= rom_pages_[(address >> 10)&3][address&1023];
|
||||
}
|
||||
|
||||
// check for a Super Chip RAM access
|
||||
if(uses_superchip_ && masked_address < 0x1100) {
|
||||
if(masked_address < 0x1080) {
|
||||
superchip_ram_[masked_address & 0x7f] = *value;
|
||||
} else {
|
||||
returnValue &= superchip_ram_[masked_address & 0x7f];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for a RAM access
|
||||
@ -263,6 +276,8 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target)
|
||||
rom_pages_[1] = &rom_[1024 & romMask];
|
||||
rom_pages_[2] = &rom_[2048 & romMask];
|
||||
rom_pages_[3] = &rom_[3072 & romMask];
|
||||
|
||||
uses_superchip_ = target.atari.uses_superchip;
|
||||
}
|
||||
|
||||
#pragma mark - Audio and Video
|
||||
|
@ -56,9 +56,14 @@ class Machine:
|
||||
virtual void crt_did_end_batch_of_frames(Outputs::CRT::CRT *crt, unsigned int number_of_frames, unsigned int number_of_unexpected_vertical_syncs);
|
||||
|
||||
private:
|
||||
// ROM information
|
||||
uint8_t *rom_, *rom_pages_[4];
|
||||
size_t rom_size_;
|
||||
|
||||
// cartridge RAM expansion store
|
||||
uint8_t superchip_ram_[128];
|
||||
bool uses_superchip_;
|
||||
|
||||
// the RIOT and TIA
|
||||
PIA mos6532_;
|
||||
std::unique_ptr<TIA> tia_;
|
||||
|
@ -27,9 +27,10 @@ void StaticAnalyser::Atari::AddTargets(
|
||||
target.tapes = tapes;
|
||||
target.cartridges = cartridges;
|
||||
target.atari.paging_model = Atari2600PagingModel::None;
|
||||
target.atari.uses_superchip = false;
|
||||
|
||||
// try to figure out the paging scheme
|
||||
/* if(!cartridges.empty())
|
||||
if(!cartridges.empty())
|
||||
{
|
||||
const std::list<Storage::Cartridge::Cartridge::Segment> &segments = cartridges.front()->get_segments();
|
||||
if(segments.size() == 1)
|
||||
@ -48,9 +49,23 @@ void StaticAnalyser::Atari::AddTargets(
|
||||
}
|
||||
StaticAnalyser::MOS6502::Disassembly disassembly =
|
||||
StaticAnalyser::MOS6502::Disassemble(segment.data, 0x1000, {entry_address, break_address}, 0x1fff);
|
||||
printf("%p", &disassembly);
|
||||
|
||||
// check for any sort of on-cartridge RAM; that might imply a Super Chip or else immediately tip the
|
||||
// hat that this is a CBS RAM+ cartridge
|
||||
if(!disassembly.internal_stores.empty())
|
||||
{
|
||||
bool writes_above_128 = false;
|
||||
for(uint16_t address : disassembly.internal_stores)
|
||||
{
|
||||
writes_above_128 |= ((address & 0x1fff) > 0x10ff) && ((address & 0x1fff) < 0x1200);
|
||||
}
|
||||
if(writes_above_128)
|
||||
target.atari.paging_model = Atari2600PagingModel::CBSRamPlus;
|
||||
else
|
||||
target.atari.uses_superchip = true;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
destination.push_back(target);
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
|
||||
break;
|
||||
|
||||
case 0x87: case 0x97: case 0x83: case 0x8f:
|
||||
instruction.operation = Instruction::SAX;
|
||||
instruction.operation = Instruction::AXS;
|
||||
break;
|
||||
case 0xa7: case 0xb7: case 0xa3: case 0xb3: case 0xaf: case 0xbf:
|
||||
instruction.operation = Instruction::LAX;
|
||||
@ -205,7 +205,7 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
|
||||
IM_INSTRUCTION(0x6b, Instruction::ARR)
|
||||
IM_INSTRUCTION(0x8b, Instruction::XAA)
|
||||
IM_INSTRUCTION(0xab, Instruction::LAX)
|
||||
IM_INSTRUCTION(0xcb, Instruction::AXS)
|
||||
IM_INSTRUCTION(0xcb, Instruction::SAX)
|
||||
IM_INSTRUCTION(0xeb, Instruction::SBC)
|
||||
case 0x93: case 0x9f:
|
||||
instruction.operation = Instruction::AHX;
|
||||
@ -259,16 +259,36 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
|
||||
disassembly.disassembly.instructions_by_address[instruction.address] = instruction;
|
||||
|
||||
// TODO: something wider-ranging than this
|
||||
if((instruction.addressing_mode == Instruction::Absolute || instruction.addressing_mode == Instruction::ZeroPage) && (instruction.operand < start_address || instruction.operand >= start_address + memory.size()))
|
||||
if(instruction.addressing_mode == Instruction::Absolute || instruction.addressing_mode == Instruction::ZeroPage)
|
||||
{
|
||||
if( instruction.operation == Instruction::STY ||
|
||||
instruction.operation == Instruction::STX ||
|
||||
instruction.operation == Instruction::STA)
|
||||
disassembly.disassembly.external_stores.insert(instruction.operand);
|
||||
if( instruction.operation == Instruction::LDY ||
|
||||
instruction.operation == Instruction::LDX ||
|
||||
instruction.operation == Instruction::LDA)
|
||||
disassembly.disassembly.external_loads.insert(instruction.operand);
|
||||
bool is_external = (instruction.operand&address_mask) < start_address || (instruction.operand&address_mask) >= start_address + memory.size();
|
||||
|
||||
switch(instruction.operation)
|
||||
{
|
||||
default: break;
|
||||
|
||||
case Instruction::LDY: case Instruction::LDX: case Instruction::LDA:
|
||||
case Instruction::LAX:
|
||||
case Instruction::AND: case Instruction::EOR: case Instruction::ORA: case Instruction::BIT:
|
||||
case Instruction::ADC: case Instruction::SBC:
|
||||
case Instruction::LAS:
|
||||
case Instruction::CMP: case Instruction::CPX: case Instruction::CPY:
|
||||
(is_external ? disassembly.disassembly.external_loads : disassembly.disassembly.internal_loads).insert(instruction.operand);
|
||||
break;
|
||||
|
||||
case Instruction::STY: case Instruction::STX: case Instruction::STA:
|
||||
case Instruction::AXS: case Instruction::AHX: case Instruction::SHX: case Instruction::SHY:
|
||||
case Instruction::TAS:
|
||||
(is_external ? disassembly.disassembly.external_stores : disassembly.disassembly.internal_stores).insert(instruction.operand);
|
||||
break;
|
||||
|
||||
case Instruction::SLO: case Instruction::RLA: case Instruction::SRE: case Instruction::RRA:
|
||||
case Instruction::DCP: case Instruction::ISC:
|
||||
case Instruction::INC: case Instruction::DEC:
|
||||
case Instruction::ASL: case Instruction::ROL: case Instruction::LSR: case Instruction::ROR:
|
||||
(is_external ? disassembly.disassembly.external_modifies : disassembly.disassembly.internal_modifies).insert(instruction.operand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// decide on overall flow control
|
||||
|
@ -65,6 +65,7 @@ struct Disassembly {
|
||||
std::map<uint16_t, Instruction> instructions_by_address;
|
||||
std::set<uint16_t> outward_calls;
|
||||
std::set<uint16_t> external_stores, external_loads, external_modifies;
|
||||
std::set<uint16_t> internal_stores, internal_loads, internal_modifies;
|
||||
};
|
||||
|
||||
Disassembly Disassemble(const std::vector<uint8_t> &memory, uint16_t start_address, std::vector<uint16_t> entry_points, uint16_t address_mask = 0xffff);
|
||||
|
@ -32,7 +32,8 @@ enum class Atari2600PagingModel {
|
||||
Atari32k,
|
||||
ActivisionStack,
|
||||
ParkerBros,
|
||||
Tigervision
|
||||
Tigervision,
|
||||
CBSRamPlus
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -57,6 +58,7 @@ struct Target {
|
||||
|
||||
struct {
|
||||
Atari2600PagingModel paging_model;
|
||||
bool uses_superchip;
|
||||
} atari;
|
||||
|
||||
struct {
|
||||
|
Loading…
Reference in New Issue
Block a user