1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00

Merge pull request #355 from TomHarte/MegaCart

Adds MegaCart support for the ColecoVision.
This commit is contained in:
Thomas Harte 2018-03-02 19:21:26 -05:00 committed by GitHub
commit fdfd72a42c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 10 deletions

View File

@ -21,15 +21,32 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
// which must be 8, 12, 16, 24 or 32 kb in size
const Storage::Cartridge::Cartridge::Segment &segment = segments.front();
const std::size_t data_size = segment.data.size();
if((data_size&8191) && (data_size != 12*1024)) continue;
if(data_size < 8192 || data_size > 32768) continue;
const std::size_t overflow = data_size&8191;
if(overflow > 8 && overflow != 512 && (data_size != 12*1024)) continue;
if(data_size < 8192) continue;
// the two first bytes must be 0xaa and 0x55, either way around
if(segment.data[0] != 0xaa && segment.data[0] != 0x55 && segment.data[1] != 0xaa && segment.data[1] != 0x55) continue;
if(segment.data[0] == segment.data[1]) continue;
// the two bytes that will be first must be 0xaa and 0x55, either way around
auto *start = &segment.data[0];
if((data_size & static_cast<std::size_t>(~8191)) > 32768) {
start = &segment.data[segment.data.size() - 16384];
}
if(start[0] != 0xaa && start[0] != 0x55 && start[1] != 0xaa && start[1] != 0x55) continue;
if(start[0] == start[1]) continue;
// probability of a random binary blob that isn't a Coleco ROM proceeding to here is 1 - 1/32768.
coleco_cartridges.push_back(cartridge);
if(!overflow) {
coleco_cartridges.push_back(cartridge);
} else {
// Size down to a multiple of 8kb and apply the start address.
std::vector<Storage::Cartridge::Cartridge::Segment> output_segments;
std::vector<uint8_t> truncated_data;
std::vector<uint8_t>::difference_type truncated_size = static_cast<std::vector<uint8_t>::difference_type>(segment.data.size()) & ~8191;
truncated_data.insert(truncated_data.begin(), segment.data.begin(), segment.data.begin() + truncated_size);
output_segments.emplace_back(0x8000, truncated_data);
coleco_cartridges.emplace_back(new Storage::Cartridge::Cartridge(output_segments));
}
}
return coleco_cartridges;

View File

@ -153,6 +153,20 @@ class ConcreteMachine:
if(!media.cartridges.empty()) {
const auto &segment = media.cartridges.front()->get_segments().front();
cartridge_ = segment.data;
if(cartridge_.size() >= 32768)
cartridge_address_limit_ = 0xffff;
else
cartridge_address_limit_ = static_cast<uint16_t>(0x8000 + cartridge_.size() - 1);
if(cartridge_.size() > 32768) {
cartridge_pages_[0] = &cartridge_[cartridge_.size() - 16384];
cartridge_pages_[1] = cartridge_.data();
is_megacart_ = true;
} else {
cartridge_pages_[0] = cartridge_.data();
cartridge_pages_[1] = cartridge_.data() + 16384;
is_megacart_ = false;
}
}
return true;
@ -182,8 +196,11 @@ class ConcreteMachine:
*cycle.value = bios_[address & 0x1fff];
} else if(address >= 0x6000 && address < 0x8000) {
*cycle.value = ram_[address & 1023];
} else if(address >= 0x8000) {
*cycle.value = cartridge_[(address - 0x8000) % cartridge_.size()]; // This probably isn't how 24kb ROMs work?
} else if(address >= 0x8000 && address <= cartridge_address_limit_) {
if(is_megacart_ && address >= 0xffc0) {
page_megacart(address);
}
*cycle.value = cartridge_pages_[(address >> 14)&1][address&0x3fff];
} else {
*cycle.value = 0xff;
}
@ -192,6 +209,8 @@ class ConcreteMachine:
case CPU::Z80::PartialMachineCycle::Write:
if(address >= 0x6000 && address < 0x8000) {
ram_[address & 1023] = *cycle.value;
} else if(is_megacart_ && address >= 0xffc0) {
page_megacart(address);
}
break;
@ -266,10 +285,14 @@ class ConcreteMachine:
}
private:
void update_audio() {
inline void page_megacart(uint16_t address) {
const std::size_t selected_start = (static_cast<std::size_t>(address&63) << 14) % cartridge_.size();
cartridge_pages_[1] = &cartridge_[selected_start];
}
inline void update_audio() {
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
}
void update_video() {
inline void update_video() {
vdp_->run_for(time_since_vdp_update_.flush());
}
@ -282,7 +305,10 @@ class ConcreteMachine:
std::vector<uint8_t> bios_;
std::vector<uint8_t> cartridge_;
uint8_t *cartridge_pages_[2];
uint8_t ram_[1024];
bool is_megacart_ = false;
uint16_t cartridge_address_limit_ = 0;
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
bool joysticks_in_keypad_mode_ = false;