1
0
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:
Thomas Harte 2018-08-30 20:24:47 -04:00
commit dab7d3db1b
4 changed files with 70 additions and 25 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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