mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-26 09:29:45 +00:00
Merge branch 'master' into 40ColumnTextCorruption
This commit is contained in:
commit
dab7d3db1b
@ -88,6 +88,14 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
uint8_t keyboard_input_ = 0x00;
|
||||
bool key_is_down_ = false;
|
||||
|
||||
uint8_t get_keyboard_input() {
|
||||
if(string_serialiser_) {
|
||||
return string_serialiser_->head() | 0x80;
|
||||
} else {
|
||||
return keyboard_input_;
|
||||
}
|
||||
}
|
||||
|
||||
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
||||
Audio::Toggle audio_toggle_;
|
||||
Outputs::Speaker::LowpassSpeaker<Audio::Toggle> speaker_;
|
||||
@ -466,11 +474,11 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
default: break;
|
||||
|
||||
case 0xc000:
|
||||
if(string_serialiser_) {
|
||||
*value = string_serialiser_->head() | 0x80;
|
||||
} else {
|
||||
*value = keyboard_input_;
|
||||
}
|
||||
*value = get_keyboard_input();
|
||||
break;
|
||||
case 0xc001: case 0xc002: case 0xc003: case 0xc004: case 0xc005: case 0xc006: case 0xc007:
|
||||
case 0xc008: case 0xc009: case 0xc00a: case 0xc00b: case 0xc00c: case 0xc00d: case 0xc00e: case 0xc00f:
|
||||
*value = (*value & 0x80) | (get_keyboard_input() & 0x7f);
|
||||
break;
|
||||
|
||||
case 0xc061: // Switch input 0.
|
||||
@ -507,22 +515,27 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
} break;
|
||||
|
||||
// The IIe-only state reads follow...
|
||||
case 0xc011: if(is_iie()) *value = (*value & 0x7f) | (language_card_.bank1 ? 0x80 : 0x00); break;
|
||||
case 0xc012: if(is_iie()) *value = (*value & 0x7f) | (language_card_.read ? 0x80 : 0x00); break;
|
||||
case 0xc013: if(is_iie()) *value = (*value & 0x7f) | (read_auxiliary_memory_ ? 0x80 : 0x00); break;
|
||||
case 0xc014: if(is_iie()) *value = (*value & 0x7f) | (write_auxiliary_memory_ ? 0x80 : 0x00); break;
|
||||
case 0xc015: if(is_iie()) *value = (*value & 0x7f) | (internal_CX_rom_ ? 0x80 : 0x00); break;
|
||||
case 0xc016: if(is_iie()) *value = (*value & 0x7f) | (alternative_zero_page_ ? 0x80 : 0x00); break;
|
||||
case 0xc017: if(is_iie()) *value = (*value & 0x7f) | (slot_C3_rom_ ? 0x80 : 0x00); break;
|
||||
case 0xc018: if(is_iie()) *value = (*value & 0x7f) | (video_->get_80_store() ? 0x80 : 0x00); break;
|
||||
case 0xc019: if(is_iie()) *value = (*value & 0x7f) | (video_->get_is_vertical_blank(cycles_since_video_update_) ? 0x00 : 0x80); break;
|
||||
case 0xc01a: if(is_iie()) *value = (*value & 0x7f) | (video_->get_text() ? 0x80 : 0x00); break;
|
||||
case 0xc01b: if(is_iie()) *value = (*value & 0x7f) | (video_->get_mixed() ? 0x80 : 0x00); break;
|
||||
case 0xc01c: if(is_iie()) *value = (*value & 0x7f) | (video_->get_page2() ? 0x80 : 0x00); break;
|
||||
case 0xc01d: if(is_iie()) *value = (*value & 0x7f) | (video_->get_high_resolution() ? 0x80 : 0x00); break;
|
||||
case 0xc01e: if(is_iie()) *value = (*value & 0x7f) | (video_->get_alternative_character_set() ? 0x80 : 0x00); break;
|
||||
case 0xc01f: if(is_iie()) *value = (*value & 0x7f) | (video_->get_80_columns() ? 0x80 : 0x00); break;
|
||||
case 0xc07f: if(is_iie()) *value = (*value & 0x7f) | (video_->get_double_high_resolution() ? 0x80 : 0x00); break;
|
||||
#define IIeSwitchRead(s) *value = get_keyboard_input(); if(is_iie()) *value = (*value & 0x7f) | (s ? 0x80 : 0x00);
|
||||
case 0xc011: IIeSwitchRead(language_card_.bank1); break;
|
||||
case 0xc012: IIeSwitchRead(language_card_.read); break;
|
||||
case 0xc013: IIeSwitchRead(read_auxiliary_memory_); break;
|
||||
case 0xc014: IIeSwitchRead(write_auxiliary_memory_); break;
|
||||
case 0xc015: IIeSwitchRead(internal_CX_rom_); break;
|
||||
case 0xc016: IIeSwitchRead(alternative_zero_page_); break;
|
||||
case 0xc017: IIeSwitchRead(slot_C3_rom_); break;
|
||||
case 0xc018: IIeSwitchRead(video_->get_80_store()); break;
|
||||
case 0xc019: IIeSwitchRead(video_->get_is_vertical_blank(cycles_since_video_update_)); break;
|
||||
case 0xc01a: IIeSwitchRead(video_->get_text()); break;
|
||||
case 0xc01b: IIeSwitchRead(video_->get_mixed()); break;
|
||||
case 0xc01c: IIeSwitchRead(video_->get_page2()); break;
|
||||
case 0xc01d: IIeSwitchRead(video_->get_high_resolution()); break;
|
||||
case 0xc01e: IIeSwitchRead(video_->get_alternative_character_set()); break;
|
||||
case 0xc01f: IIeSwitchRead(video_->get_80_columns()); break;
|
||||
#undef IIeSwitchRead
|
||||
|
||||
case 0xc07f:
|
||||
if(is_iie()) *value = (*value & 0x7f) | (video_->get_double_high_resolution() ? 0x80 : 0x00);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Write-only switches. All IIe as currently implemented.
|
||||
@ -640,7 +653,8 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xc030:
|
||||
case 0xc030: case 0xc031: case 0xc032: case 0xc033: case 0xc034: case 0xc035: case 0xc036: case 0xc037:
|
||||
case 0xc038: case 0xc039: case 0xc03a: case 0xc03b: case 0xc03c: case 0xc03d: case 0xc03e: case 0xc03f:
|
||||
update_audio();
|
||||
audio_toggle_.set_output(!audio_toggle_.get_output());
|
||||
break;
|
||||
|
@ -75,19 +75,24 @@ std::shared_ptr<Track> AppleDSK::get_track_at_position(Track::Address address) {
|
||||
// In either case below, the code aims for exactly 50,000 bits per track.
|
||||
if(sectors_per_track_ == 16) {
|
||||
// Write gap 1.
|
||||
segment += Encodings::AppleGCR::six_and_two_sync(16);
|
||||
segment += Encodings::AppleGCR::six_and_two_sync(24);
|
||||
|
||||
// Write the sectors.
|
||||
for(uint8_t c = 0; c < 16; ++c) {
|
||||
segment += Encodings::AppleGCR::header(254, track, c);
|
||||
segment += Encodings::AppleGCR::header(is_prodos_ ? 0x01 : 0xfe, track, c); // Volume number is 0xfe for DOS 3.3, 0x01 for Pro-DOS.
|
||||
segment += Encodings::AppleGCR::six_and_two_sync(7); // Gap 2: 7 sync words.
|
||||
segment += Encodings::AppleGCR::six_and_two_data(&track_data[logical_sector_for_physical_sector(c) * 256]);
|
||||
segment += Encodings::AppleGCR::six_and_two_sync(16); // Gap 3: 16 sync words.
|
||||
segment += Encodings::AppleGCR::six_and_two_sync(20); // Gap 3: 20 sync words.
|
||||
}
|
||||
} else {
|
||||
// TODO: 5 and 3, 13-sector format. If DSK actually supports it?
|
||||
}
|
||||
|
||||
// Apply inter-track skew; skew is about 40ms between each track; assuming 300RPM that's
|
||||
// 1/5th of a revolution.
|
||||
const size_t offset_in_fifths = address.position.as_int() % 5;
|
||||
segment.rotate_right(offset_in_fifths * segment.data.size() / 5);
|
||||
|
||||
return std::make_shared<PCMTrack>(segment);
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,25 @@ PCMSegment &PCMSegment::operator +=(const PCMSegment &rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void PCMSegment::rotate_right(size_t length) {
|
||||
length %= data.size();
|
||||
if(!length) return;
|
||||
|
||||
// To rotate to the right, front-insert the proper number
|
||||
// of bits from the end and then resize. To rotate to
|
||||
// the left, do the opposite.
|
||||
std::vector<uint8_t> data_copy;
|
||||
if(length > 0) {
|
||||
data_copy.insert(data_copy.end(), data.end() - static_cast<off_t>(length), data.end());
|
||||
data.erase(data.end() - static_cast<off_t>(length), data.end());
|
||||
data.insert(data.begin(), data_copy.begin(), data_copy.end());
|
||||
} else {
|
||||
data_copy.insert(data_copy.end(), data.begin(), data.begin() - static_cast<off_t>(length));
|
||||
data.erase(data.begin(), data.begin() - static_cast<off_t>(length));
|
||||
data.insert(data.end(), data_copy.begin(), data_copy.end());
|
||||
}
|
||||
}
|
||||
|
||||
Storage::Disk::Track::Event PCMSegmentEventSource::get_next_event() {
|
||||
// track the initial bit pointer for potentially considering whether this was an
|
||||
// initial index hole or a subsequent one later on
|
||||
|
@ -105,6 +105,13 @@ struct PCMSegment {
|
||||
data.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
Rotates all bits in this segment by @c length bits.
|
||||
|
||||
@c length is signed; to rotate left provide a negative number.
|
||||
*/
|
||||
void rotate_right(size_t length);
|
||||
|
||||
/*!
|
||||
Produces a byte buffer where the contents of @c data are serialised into bytes
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user