From b753690d5eede981a30d10331d2d65997e4c43d6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 21 Jun 2016 22:12:01 -0400 Subject: [PATCH 1/4] Made an attempt to adjust the 6560 to a model compatible with that advocated by the available documentation. Exact decision timing may need further work. --- Components/6560/6560.cpp | 137 +++++++++++++++++++-------------------- Components/6560/6560.hpp | 57 ++++++++++------ 2 files changed, 105 insertions(+), 89 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index e63002535..b729095a4 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -60,31 +60,31 @@ MOS6560::MOS6560() : void MOS6560::set_register(int address, uint8_t value) { address &= 0xf; - _registers[address] = value; + _registers.direct_values[address] = value; switch(address) { case 0x0: - _interlaced = !!(value&0x80); - _first_column_location = value & 0x7f; + _registers.interlaced = !!(value&0x80); + _registers.first_column_location = value & 0x7f; break; case 0x1: - _first_row_location = value; + _registers.first_row_location = value; break; case 0x2: - _number_of_columns = value & 0x7f; - _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x3c00) | ((value & 0x80) << 2)); + _registers.number_of_columns = value & 0x7f; + _registers.video_matrix_start_address = (uint16_t)((_registers.video_matrix_start_address & 0x3c00) | ((value & 0x80) << 2)); break; case 0x3: - _number_of_rows = (value >> 1)&0x3f; - _tall_characters = !!(value&0x01); + _registers.number_of_rows = (value >> 1)&0x3f; + _registers.tall_characters = !!(value&0x01); break; case 0x5: - _character_cell_start_address = (uint16_t)((value & 0x0f) << 10); - _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x0200) | ((value & 0xf0) << 6)); + _registers.character_cell_start_address = (uint16_t)((value & 0x0f) << 10); + _registers.video_matrix_start_address = (uint16_t)((_registers.video_matrix_start_address & 0x0200) | ((value & 0xf0) << 6)); break; case 0xa: @@ -97,7 +97,7 @@ void MOS6560::set_register(int address, uint8_t value) case 0xe: update_audio(); - _auxiliary_colour = _colours[value >> 4]; + _registers.auxiliary_colour = _colours[value >> 4]; _speaker.set_volume(value & 0xf); break; @@ -107,9 +107,9 @@ void MOS6560::set_register(int address, uint8_t value) output_border(_cycles_in_state * 4); _cycles_in_state = 0; } - _invertedCells = !((value >> 3)&1); - _borderColour = _colours[value & 0x07]; - _backgroundColour = _colours[value >> 4]; + _registers.invertedCells = !((value >> 3)&1); + _registers.borderColour = _colours[value & 0x07]; + _registers.backgroundColour = _colours[value >> 4]; break; // TODO: audio, primarily @@ -124,8 +124,8 @@ uint8_t MOS6560::get_register(int address) address &= 0xf; switch(address) { - default: return _registers[address]; - case 0x03: return (uint8_t)(_vertical_counter << 7) | (_registers[3] & 0x7f); + default: return _registers.direct_values[address]; + case 0x03: return (uint8_t)(_vertical_counter << 7) | (_registers.direct_values[3] & 0x7f); case 0x04: return (_vertical_counter >> 1) & 0xff; } } @@ -133,7 +133,7 @@ uint8_t MOS6560::get_register(int address) void MOS6560::output_border(unsigned int number_of_cycles) { uint8_t *colour_pointer = _crt->allocate_write_area(1); - if(colour_pointer) *colour_pointer = _borderColour; + if(colour_pointer) *colour_pointer = _registers.borderColour; _crt->output_level(number_of_cycles); } @@ -144,64 +144,62 @@ uint16_t MOS6560::get_address() // keep track of internal time relative to this scanline _horizontal_counter++; - - // check for end of scanline if(_horizontal_counter == 65) { - _horizontal_counter = 0; - - _vertical_counter++; - _column_counter = -1; - - if(_vertical_counter == (_interlaced ? (_is_odd_frame ? 262 : 263) : 261)) + if(_horizontal_drawing_latch) { - _is_odd_frame ^= true; - _vertical_counter = 0; - _row_counter = -1; - } - - if(_row_counter >= 0) - { - _row_counter++; - if(_row_counter == _number_of_rows*(_tall_characters ? 16 : 8)) _row_counter = -1; - } - else if(_vertical_counter == _first_row_location * 2) - { - _video_matrix_line_address_counter = _video_matrix_start_address; - _row_counter = 0; - } - } - - if(_column_counter >= 0) - { - _column_counter++; - if(_column_counter == _number_of_columns*2) - { - _column_counter = -1; - if((_row_counter&(_tall_characters ? 15 : 7)) == (_tall_characters ? 15 : 7)) - { - _video_matrix_line_address_counter = _video_matrix_address_counter; + _current_character_row++; + if( + (_current_character_row == 16) || + (_current_character_row == 8 && !_registers.tall_characters) + ) { + _current_character_row = 0; + _video_matrix_address_counter += _columns_this_line; + _current_row++; } + + _current_column = 0; + _columns_this_line = -1; + } + + _horizontal_counter = 0; + _horizontal_drawing_latch = false; + + _vertical_counter ++; + if(_vertical_counter == (_registers.interlaced ? (_is_odd_frame ? 262 : 263) : 261)) + { + _vertical_counter = 0; + + _is_odd_frame ^= true; + _current_row = 0; + _rows_this_field = -1; + _vertical_drawing_latch = false; + _video_matrix_address_counter = 0; + _current_character_row = 0; } } - else if(_horizontal_counter == _first_column_location) - { - _column_counter = 0; - _video_matrix_address_counter = _video_matrix_line_address_counter; - } + + // check for vertical starting events + if(_vertical_drawing_latch && _rows_this_field < 0) _rows_this_field = _registers.number_of_rows; + _vertical_drawing_latch |= _registers.first_row_location == (_vertical_counter >> 1); // TODO: this test should be delayed a cycle + + // check for horizontal starting events + if(_horizontal_drawing_latch && _columns_this_line < 0) _columns_this_line = _registers.number_of_columns; + _horizontal_drawing_latch |= + _vertical_drawing_latch && (_current_row < _rows_this_field) && (_horizontal_counter == _registers.first_column_location); // determine output state; colour burst and sync timing are currently a guess if(_horizontal_counter > 61) _this_state = State::ColourBurst; else if(_horizontal_counter > 57) _this_state = State::Sync; else { - _this_state = (_column_counter >= 0 && _row_counter >= 0) ? State::Pixels : State::Border; + _this_state = (_horizontal_drawing_latch && _current_column < _columns_this_line*2) ? State::Pixels : State::Border; } // apply vertical sync if( - (_vertical_counter < 3 && (_is_odd_frame || !_interlaced)) || - (_interlaced && + (_vertical_counter < 3 && (_is_odd_frame || !_registers.interlaced)) || + (_registers.interlaced && ( (_vertical_counter == 0 && _horizontal_counter > 32) || (_vertical_counter == 1) || (_vertical_counter == 2) || @@ -235,7 +233,7 @@ uint16_t MOS6560::get_address() if(_this_state == State::Pixels) { /* - Per http://tinyvga.com/6561 : + Per http:tinyvga.com/6561 : The basic video timing is very simple. For every character the VIC-I is about to display, it first fetches the @@ -248,15 +246,13 @@ uint16_t MOS6560::get_address() reading from unconnected address space, such as $9100-$910f, you can read the data fetched by the videochip on the previous clock cycle.) */ - if(_column_counter&1) + if(_current_column&1) { - return _character_cell_start_address + (_character_code*(_tall_characters ? 16 : 8)) + (_row_counter&(_tall_characters ? 15 : 7)); + return _registers.character_cell_start_address + (_character_code*(_registers.tall_characters ? 16 : 8)) + _current_character_row; } else { - uint16_t result = _video_matrix_address_counter; - _video_matrix_address_counter++; - return result; + return (uint16_t)(_registers.video_matrix_start_address + _video_matrix_address_counter + (_current_column >> 1)); } } @@ -271,7 +267,7 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) // and to adjust the signalling to the CRT above? if(_this_state == State::Pixels) { - if(_column_counter&1) + if(_current_column&1) { _character_value = value; @@ -281,14 +277,14 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) if(!(_character_colour&0x8)) { uint8_t colours[2]; - if(_invertedCells) + if(_registers.invertedCells) { colours[0] = cell_colour; - colours[1] = _backgroundColour; + colours[1] = _registers.backgroundColour; } else { - colours[0] = _backgroundColour; + colours[0] = _registers.backgroundColour; colours[1] = cell_colour; } pixel_pointer[0] = colours[(_character_value >> 7)&1]; @@ -302,7 +298,7 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) } else { - uint8_t colours[4] = {_backgroundColour, _borderColour, cell_colour, _auxiliary_colour}; + uint8_t colours[4] = {_registers.backgroundColour, _registers.borderColour, cell_colour, _registers.auxiliary_colour}; pixel_pointer[0] = pixel_pointer[1] = colours[(_character_value >> 6)&3]; pixel_pointer[2] = @@ -320,6 +316,7 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) _character_code = value; _character_colour = colour_value; } + _current_column++; } } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 4c041a962..5a2e75519 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -56,6 +56,8 @@ class MOS6560 { private: std::unique_ptr _crt; + + // audio state class Speaker: public ::Outputs::Filter { public: Speaker(); @@ -72,38 +74,55 @@ class MOS6560 { uint8_t _control_registers[4]; uint8_t _volume; } _speaker; + unsigned int _cycles_since_speaker_update; + void update_audio(); - bool _interlaced, _tall_characters; - uint8_t _first_column_location, _first_row_location; - uint8_t _number_of_columns, _number_of_rows; - uint16_t _character_cell_start_address, _video_matrix_start_address; - uint8_t _backgroundColour, _borderColour, _auxiliary_colour; - bool _invertedCells; + // register state + struct { + bool interlaced, tall_characters; + uint8_t first_column_location, first_row_location; + uint8_t number_of_columns, number_of_rows; + uint16_t character_cell_start_address, video_matrix_start_address; + uint8_t backgroundColour, borderColour, auxiliary_colour; + bool invertedCells; - int _horizontal_counter, _vertical_counter; - bool _did_output_graphics; - - int _column_counter, _row_counter; - uint16_t _video_matrix_address_counter, _video_matrix_line_address_counter; + uint8_t direct_values[16]; + } _registers; + // output state enum State { Sync, ColourBurst, Border, Pixels } _this_state, _output_state; unsigned int _cycles_in_state; + // counters that cover an entire field + int _horizontal_counter, _vertical_counter; + + // latches dictating start and length of drawing + bool _vertical_drawing_latch, _horizontal_drawing_latch; + int _rows_this_field, _columns_this_line; + + // current drawing position counter + int _current_column; + int _current_row; + uint16_t _current_character_row; + uint16_t _video_matrix_address_counter; + + // address counters +// uint16_t _ +// int _column_counter, _row_counter; +// uint16_t _video_matrix_address_counter, _video_matrix_line_address_counter; + + // data latched from the bus uint8_t _character_code, _character_colour, _character_value; - uint8_t *pixel_pointer; - - uint8_t _registers[16]; - uint8_t _colours[16]; - bool _is_odd_frame; - void output_border(unsigned int number_of_cycles); + // lookup table from 6560 colour index to appropriate PAL/NTSC value + uint8_t _colours[16]; - unsigned int _cycles_since_speaker_update; - void update_audio(); + uint8_t *pixel_pointer; + void output_border(unsigned int number_of_cycles); }; } From e05003c17651ef9ba1f3dd4fc1b1bd759b1cbf8e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Jun 2016 17:34:42 -0400 Subject: [PATCH 2/4] Discovered that the VIC and the VIAs can be simultaneously selected. Adjusted bus appropriately. --- Machines/Vic-20/Vic20.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 17973f035..b1c0b5ad7 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -47,35 +47,36 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin // run the phase-2 part of the cycle, which is whatever the 6502 said it should be if(isReadOperation(operation)) { - *value = read_memory(address); - if((address&0xfff0) == 0x9000) + uint8_t result = read_memory(address); + if((address&0xff00) == 0x9000) { - *value = _mos6560->get_register(address - 0x9000); + result &= _mos6560->get_register(address); } - else if((address&0xfff0) == 0x9110) + if((address&0xfc10) == 0x9010) { - *value = _userPortVIA.get_register(address - 0x9110); + result &= _userPortVIA.get_register(address); } - else if((address&0xfff0) == 0x9120) + if((address&0xfc20) == 0x9020) { - *value = _keyboardVIA.get_register(address - 0x9120); + result &= _keyboardVIA.get_register(address); } + *value = result; } else { uint8_t *ram = ram_pointer(address); if(ram) *ram = *value; - else if((address&0xfff0) == 0x9000) + if((address&0xff00) == 0x9000) { - _mos6560->set_register(address - 0x9000, *value); + _mos6560->set_register(address, *value); } - else if((address&0xfff0) == 0x9110) + if((address&0xfc10) == 0x9010) { - _userPortVIA.set_register(address - 0x9110, *value); + _userPortVIA.set_register(address, *value); } - else if((address&0xfff0) == 0x9120) + if((address&0xfc20) == 0x9020) { - _keyboardVIA.set_register(address - 0x9120, *value); + _keyboardVIA.set_register(address, *value); } } From 359ffb9aa7f16a40858b25a075d83e404889862d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 23 Jun 2016 07:32:24 -0400 Subject: [PATCH 3/4] Made some attempt to implement what appears to be the proper address generation logic. --- Components/6560/6560.cpp | 177 ++++++++++++++++++++++----------------- Components/6560/6560.hpp | 23 +++-- 2 files changed, 118 insertions(+), 82 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index b729095a4..7fc576c69 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -29,34 +29,59 @@ MOS6560::MOS6560() : "return mix(y, step(yC, 14) * chroma, amplitude);" "}"); - // set up colours table - // 0 - // 2, 6, 9, B, - // 4, 5, 8, A, C, E - // 3, 7, D, F - // 1 - uint8_t luminances[16] = { // range is 0–4 - 0, 4, 1, 3, 2, 2, 1, 3, - 2, 1, 2, 1, 2, 3, 2, 3 - }; -// uint8_t pal_chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance" -// 15, 15, 5, 13, 2, 10, 0, 8, -// 6, 7, 5, 13, 2, 10, 0, 8, -// }; - uint8_t ntsc_chrominances[16] = { - 15, 15, 2, 10, 4, 12, 6, 14, - 0, 8, 2, 10, 4, 12, 6, 14, - }; - for(int c = 0; c < 16; c++) - { - _colours[c] = (uint8_t)((luminances[c] << 4) | ntsc_chrominances[c]); - } + // default to NTSC + set_output_mode(OutputMode::NTSC); // show only the centre _crt->set_visible_area(_crt->get_rect_for_area(16, 237, 11*4, 55*4, 4.0f / 3.0f)); _speaker.set_input_rate(255681.75); // assuming NTSC; clock rate / 4 } +void MOS6560::set_output_mode(OutputMode output_mode) +{ + uint8_t luminances[16] = { // range is 0–4 + 0, 4, 1, 3, 2, 2, 1, 3, + 2, 1, 2, 1, 2, 3, 2, 3 + }; + uint8_t pal_chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance" + 15, 15, 5, 13, 2, 10, 0, 8, + 6, 7, 5, 13, 2, 10, 0, 8, + }; + uint8_t ntsc_chrominances[16] = { + 15, 15, 2, 10, 4, 12, 6, 14, + 0, 8, 2, 10, 4, 12, 6, 14, + }; + uint8_t *chrominances; + Outputs::CRT::DisplayType display_type; + + switch(output_mode) + { + case OutputMode::PAL: + chrominances = pal_chrominances; + display_type = Outputs::CRT::PAL50; + _timing.cycles_per_line = 71; + _timing.lines_per_progressive_field = 312; + _timing.supports_interlacing = false; + break; + + case OutputMode::NTSC: + chrominances = ntsc_chrominances; + display_type = Outputs::CRT::NTSC60; + _timing.cycles_per_line = 65; + _timing.lines_per_progressive_field = 261; + _timing.supports_interlacing = true; + break; + } + + _crt->set_new_display_type((unsigned int)(_timing.cycles_per_line*4), display_type); + for(int c = 0; c < 16; c++) + { + _colours[c] = (uint8_t)((luminances[c] << 4) | chrominances[c]); + } +} + +// TODO: set clock rate + void MOS6560::set_register(int address, uint8_t value) { address &= 0xf; @@ -64,7 +89,7 @@ void MOS6560::set_register(int address, uint8_t value) switch(address) { case 0x0: - _registers.interlaced = !!(value&0x80); + _registers.interlaced = !!(value&0x80) && _timing.supports_interlacing; _registers.first_column_location = value & 0x7f; break; @@ -142,9 +167,12 @@ uint16_t MOS6560::get_address() // keep track of the amount of time since the speaker was updated; lazy updates are applied _cycles_since_speaker_update++; + // keep an old copy of the vertical count because that test is a cycle later than the actual changes + int previous_vertical_counter = _vertical_counter; + // keep track of internal time relative to this scanline _horizontal_counter++; - if(_horizontal_counter == 65) + if(_horizontal_counter == _timing.cycles_per_line) { if(_horizontal_drawing_latch) { @@ -154,19 +182,19 @@ uint16_t MOS6560::get_address() (_current_character_row == 8 && !_registers.tall_characters) ) { _current_character_row = 0; - _video_matrix_address_counter += _columns_this_line; _current_row++; } - _current_column = 0; + _pixel_line_cycle = -1; _columns_this_line = -1; + _column_counter = -1; } _horizontal_counter = 0; _horizontal_drawing_latch = false; _vertical_counter ++; - if(_vertical_counter == (_registers.interlaced ? (_is_odd_frame ? 262 : 263) : 261)) + if(_vertical_counter == (_registers.interlaced ? (_is_odd_frame ? 262 : 263) : _timing.lines_per_progressive_field)) { _vertical_counter = 0; @@ -174,26 +202,60 @@ uint16_t MOS6560::get_address() _current_row = 0; _rows_this_field = -1; _vertical_drawing_latch = false; - _video_matrix_address_counter = 0; + _base_video_matrix_address_counter = 0; _current_character_row = 0; } } // check for vertical starting events - if(_vertical_drawing_latch && _rows_this_field < 0) _rows_this_field = _registers.number_of_rows; - _vertical_drawing_latch |= _registers.first_row_location == (_vertical_counter >> 1); // TODO: this test should be delayed a cycle + _vertical_drawing_latch |= _registers.first_row_location == (previous_vertical_counter >> 1); + _horizontal_drawing_latch |= _vertical_drawing_latch && (_horizontal_counter == _registers.first_column_location); - // check for horizontal starting events - if(_horizontal_drawing_latch && _columns_this_line < 0) _columns_this_line = _registers.number_of_columns; - _horizontal_drawing_latch |= - _vertical_drawing_latch && (_current_row < _rows_this_field) && (_horizontal_counter == _registers.first_column_location); + if(_pixel_line_cycle >= 0) _pixel_line_cycle++; + switch(_pixel_line_cycle) + { + case -1: + if(_horizontal_drawing_latch) + { + _pixel_line_cycle = 0; + _video_matrix_address_counter = _base_video_matrix_address_counter; + } + break; + case 1: _columns_this_line = _registers.number_of_columns; break; + case 2: if(_rows_this_field < 0) _rows_this_field = _registers.number_of_rows; break; + case 3: if(_current_row < _rows_this_field) _column_counter = 0; break; + } + uint16_t fetch_address = 0x1c; + if(_column_counter >= 0 && _column_counter < _columns_this_line*2) + { + if(_column_counter&1) + { + fetch_address = _registers.character_cell_start_address + (_character_code*(_registers.tall_characters ? 16 : 8)) + _current_character_row; + } + else + { + fetch_address = (uint16_t)(_registers.video_matrix_start_address + _video_matrix_address_counter); + _video_matrix_address_counter++; + if( + (_current_character_row == 15) || + (_current_character_row == 7 && !_registers.tall_characters) + ) { + _base_video_matrix_address_counter = _video_matrix_address_counter; + } + } + } + return fetch_address; +} + +void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) +{ // determine output state; colour burst and sync timing are currently a guess - if(_horizontal_counter > 61) _this_state = State::ColourBurst; - else if(_horizontal_counter > 57) _this_state = State::Sync; + if(_horizontal_counter > _timing.cycles_per_line-4) _this_state = State::ColourBurst; + else if(_horizontal_counter > _timing.cycles_per_line-7) _this_state = State::Sync; else { - _this_state = (_horizontal_drawing_latch && _current_column < _columns_this_line*2) ? State::Pixels : State::Border; + _this_state = (_column_counter >= 0 && _column_counter < _columns_this_line*2) ? State::Pixels : State::Border; } // apply vertical sync @@ -229,45 +291,9 @@ uint16_t MOS6560::get_address() } _cycles_in_state++; - // compute the address if(_this_state == State::Pixels) { - /* - Per http:tinyvga.com/6561 : - - The basic video timing is very simple. For - every character the VIC-I is about to display, it first fetches the - character code and colour, then the character appearance (from the - character generator memory). The character codes are read on every - raster line, thus making every line a "bad line". When the raster - beam is outside of the text window, the videochip reads from $001c for - most time. (Some videochips read from $181c instead.) The address - occasionally varies, but it might also be due to a flaky bus. (By - reading from unconnected address space, such as $9100-$910f, you can - read the data fetched by the videochip on the previous clock cycle.) - */ - if(_current_column&1) - { - return _registers.character_cell_start_address + (_character_code*(_registers.tall_characters ? 16 : 8)) + _current_character_row; - } - else - { - return (uint16_t)(_registers.video_matrix_start_address + _video_matrix_address_counter + (_current_column >> 1)); - } - } - - return 0x1c; -} - -void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) -{ - // TODO: this isn't correct, as _character_value will be - // accessed second, then output will roll over. Probably it's - // correct (given the delays upstream) to output all 8 on an &1 - // and to adjust the signalling to the CRT above? - if(_this_state == State::Pixels) - { - if(_current_column&1) + if(_column_counter&1) { _character_value = value; @@ -316,7 +342,8 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) _character_code = value; _character_colour = colour_value; } - _current_column++; + + _column_counter++; } } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 5a2e75519..562e1b754 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -28,6 +28,14 @@ class MOS6560 { Outputs::CRT::CRT *get_crt() { return _crt.get(); } Outputs::Speaker *get_speaker() { return &_speaker; } + enum OutputMode { + PAL, NTSC + }; + /*! + Sets the output mode to either PAL or NTSC. + */ + void set_output_mode(OutputMode output_mode); + /*! Impliedly runs the 6560 for a single cycle, returning the next address that it puts on the bus. */ @@ -103,15 +111,10 @@ class MOS6560 { int _rows_this_field, _columns_this_line; // current drawing position counter - int _current_column; + int _pixel_line_cycle, _column_counter; int _current_row; uint16_t _current_character_row; - uint16_t _video_matrix_address_counter; - - // address counters -// uint16_t _ -// int _column_counter, _row_counter; -// uint16_t _video_matrix_address_counter, _video_matrix_line_address_counter; + uint16_t _video_matrix_address_counter, _base_video_matrix_address_counter; // data latched from the bus uint8_t _character_code, _character_colour, _character_value; @@ -123,6 +126,12 @@ class MOS6560 { uint8_t *pixel_pointer; void output_border(unsigned int number_of_cycles); + + struct { + int cycles_per_line; + int lines_per_progressive_field; + bool supports_interlacing; + } _timing; }; } From 3c9183d034a704bfba64332cbfe54024f7ed19aa Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 23 Jun 2016 20:43:29 -0400 Subject: [PATCH 4/4] Improved some commenting. --- Components/6560/6560.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 7fc576c69..c15968752 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -137,7 +137,7 @@ void MOS6560::set_register(int address, uint8_t value) _registers.backgroundColour = _colours[value >> 4]; break; - // TODO: audio, primarily + // TODO: the lightpen, etc default: break; @@ -250,6 +250,9 @@ uint16_t MOS6560::get_address() void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { + // TODO: there should be a further two-cycle delay on pixels being output; the reverse bit should + // divide the byte it is set for 3:1 and then continue as usual. + // determine output state; colour burst and sync timing are currently a guess if(_horizontal_counter > _timing.cycles_per_line-4) _this_state = State::ColourBurst; else if(_horizontal_counter > _timing.cycles_per_line-7) _this_state = State::Sync;