1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-17 13:29:02 +00:00

Merge pull request #410 from TomHarte/VicNTSC

Corrects NTSC VIC raster register timing.
This commit is contained in:
Thomas Harte 2018-04-11 10:29:46 -04:00 committed by GitHub
commit 8d4d5d1f46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 25 deletions

View File

@ -149,6 +149,9 @@ void Analyser::Static::Commodore::AddTargets(const Media &media, std::vector<std
target->region = Analyser::Static::Commodore::Target::Region::American;
}
// Attach a 1540 if there are any disks here.
target->has_c1540 = !target->media.disks.empty();
destination.push_back(std::move(target));
}
}

View File

@ -106,7 +106,7 @@ static uint8_t noise_pattern[] = {
// means every second cycle, etc.
void AudioGenerator::get_samples(std::size_t number_of_samples, int16_t *target) {
for(unsigned int c = 0; c < number_of_samples; c++) {
for(unsigned int c = 0; c < number_of_samples; ++c) {
update(0, 2, shift);
update(1, 1, shift);
update(2, 0, shift);
@ -124,7 +124,7 @@ void AudioGenerator::get_samples(std::size_t number_of_samples, int16_t *target)
}
void AudioGenerator::skip_samples(std::size_t number_of_samples) {
for(unsigned int c = 0; c < number_of_samples; c++) {
for(unsigned int c = 0; c < number_of_samples; ++c) {
update(0, 2, shift);
update(1, 1, shift);
update(2, 0, shift);

View File

@ -100,10 +100,10 @@ template <class T> class MOS6560 {
// Luminances are encoded trivially: on a 0255 scale.
const uint8_t luminances[16] = {
0, 255, 60, 189,
80, 144, 40, 227,
90, 161, 207, 227,
200, 196, 160, 196
0, 255, 64, 192,
128, 128, 64, 192,
128, 192, 128, 255,
192, 192, 128, 255
};
// Chrominances are encoded such that 0128 is a complete revolution of phase;
@ -130,6 +130,7 @@ template <class T> class MOS6560 {
display_type = Outputs::CRT::DisplayType::PAL50;
timing_.cycles_per_line = 71;
timing_.line_counter_increment_offset = 0;
timing_.final_line_increment_position = 71;
timing_.lines_per_progressive_field = 312;
timing_.supports_interlacing = false;
break;
@ -138,7 +139,8 @@ template <class T> class MOS6560 {
chrominances = ntsc_chrominances;
display_type = Outputs::CRT::DisplayType::NTSC60;
timing_.cycles_per_line = 65;
timing_.line_counter_increment_offset = 65 - 33; // TODO: this is a bit of a hack; separate vertical and horizontal counting
timing_.line_counter_increment_offset = 40;
timing_.final_line_increment_position = 58;
timing_.lines_per_progressive_field = 261;
timing_.supports_interlacing = true;
break;
@ -176,7 +178,6 @@ template <class T> class MOS6560 {
// keep track of internal time relative to this scanline
horizontal_counter_++;
full_frame_counter_++;
if(horizontal_counter_ == timing_.cycles_per_line) {
if(horizontal_drawing_latch_) {
current_character_row_++;
@ -198,9 +199,8 @@ template <class T> class MOS6560 {
horizontal_drawing_latch_ = false;
vertical_counter_ ++;
if(vertical_counter_ == (registers_.interlaced ? (is_odd_frame_ ? 262 : 263) : timing_.lines_per_progressive_field)) {
if(vertical_counter_ == lines_this_field()) {
vertical_counter_ = 0;
full_frame_counter_ = 0;
if(output_mode_ == OutputMode::NTSC) is_odd_frame_ ^= true;
current_row_ = 0;
@ -262,7 +262,7 @@ template <class T> class MOS6560 {
// apply vertical sync
if(
(vertical_counter_ < 3 && (is_odd_frame_ || !registers_.interlaced)) ||
(vertical_counter_ < 3 && is_odd_frame()) ||
(registers_.interlaced &&
(
(vertical_counter_ == 0 && horizontal_counter_ > 32) ||
@ -414,11 +414,10 @@ template <class T> class MOS6560 {
*/
uint8_t get_register(int address) {
address &= 0xf;
int current_line = (full_frame_counter_ + timing_.line_counter_increment_offset) / timing_.cycles_per_line;
switch(address) {
default: return registers_.direct_values[address];
case 0x03: return static_cast<uint8_t>(current_line << 7) | (registers_.direct_values[3] & 0x7f);
case 0x04: return (current_line >> 1) & 0xff;
case 0x03: return static_cast<uint8_t>(raster_value() << 7) | (registers_.direct_values[3] & 0x7f);
case 0x04: return (raster_value() >> 1) & 0xff;
}
}
@ -453,7 +452,29 @@ template <class T> class MOS6560 {
unsigned int cycles_in_state_;
// counters that cover an entire field
int horizontal_counter_ = 0, vertical_counter_ = 0, full_frame_counter_;
int horizontal_counter_ = 0, vertical_counter_ = 0;
const int lines_this_field() {
// Necessary knowledge here: only the NTSC 6560 supports interlaced video.
return registers_.interlaced ? (is_odd_frame_ ? 262 : 263) : timing_.lines_per_progressive_field;
}
const int raster_value() {
const int bonus_line = (horizontal_counter_ + timing_.line_counter_increment_offset) / timing_.cycles_per_line;
const int line = vertical_counter_ + bonus_line;
const int final_line = lines_this_field();
if(line < final_line)
return line;
if(is_odd_frame()) {
return (horizontal_counter_ >= timing_.final_line_increment_position) ? 0 : final_line - 1;
} else {
return line % final_line;
}
// Cf. http://www.sleepingelephant.com/ipw-web/bulletin/bb/viewtopic.php?f=14&t=7237&start=15#p80737
}
bool is_odd_frame() {
return is_odd_frame_ || !registers_.interlaced;
}
// latches dictating start and length of drawing
bool vertical_drawing_latch_, horizontal_drawing_latch_;
@ -483,6 +504,7 @@ template <class T> class MOS6560 {
struct {
int cycles_per_line;
int line_counter_increment_offset;
int final_line_increment_position;
int lines_per_progressive_field;
bool supports_interlacing;
} timing_;

View File

@ -374,7 +374,7 @@ class ConcreteMachine:
type_string(target->loading_command);
}
if(target->media.disks.size()) {
if(commodore_target_.has_c1540) {
// construct the 1540
c1540_.reset(new ::Commodore::C1540::Machine(Commodore::C1540::Machine::C1540));
@ -546,12 +546,12 @@ class ConcreteMachine:
if(isReadOperation(operation)) {
uint8_t result = processor_read_memory_map_[address >> 10] ? processor_read_memory_map_[address >> 10][address & 0x3ff] : 0xff;
if((address&0xfc00) == 0x9000) {
if((address&0xff00) == 0x9000) {
if(!(address&0x100)) {
update_video();
result &= mos6560_->get_register(address);
}
if((address&0xfc10) == 0x9010) result &= user_port_via_.get_register(address);
if((address&0xfc20) == 0x9020) result &= keyboard_via_.get_register(address);
if(address & 0x10) result &= user_port_via_.get_register(address);
if(address & 0x20) result &= keyboard_via_.get_register(address);
}
*value = result;
@ -630,13 +630,17 @@ class ConcreteMachine:
update_video();
ram[address & 0x3ff] = *value;
}
// Anything between 0x9000 and 0x9400 is the IO area.
if((address&0xfc00) == 0x9000) {
if((address&0xff00) == 0x9000) {
// The VIC is selected by bit 8 = 0
if(!(address&0x100)) {
update_video();
mos6560_->set_register(address, *value);
}
if((address&0xfc10) == 0x9010) user_port_via_.set_register(address, *value);
if((address&0xfc20) == 0x9020) keyboard_via_.set_register(address, *value);
// The first VIA is selected by bit 4 = 1.
if(address & 0x10) user_port_via_.set_register(address, *value);
// The second VIA is selected by bit 5 = 1.
if(address & 0x20) keyboard_via_.set_register(address, *value);
}
}

View File

@ -20,11 +20,11 @@
<rect key="contentRect" x="196" y="240" width="600" height="165"/>
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="768"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="600" height="205"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="0.0" y="0.0" width="600" height="165"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tabView translatesAutoresizingMaskIntoConstraints="NO" id="VUb-QG-x7c">
<rect key="frame" x="13" y="51" width="574" height="140"/>
<rect key="frame" x="13" y="51" width="574" height="100"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="Acorn Electron" identifier="electron" id="muc-z9-Vqc">
@ -334,6 +334,9 @@
<buttonCell key="cell" type="push" title="Choose" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="MnM-xo-4Qa">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="createMachine:" target="-2" id="2wo-Zv-H4f"/>