1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +00:00

Made an attempt to reintroduce interlacing and screen modes with gaps. Something's wrong with synchronisation though, so most likely I'm outputting a bad signal.

This commit is contained in:
Thomas Harte 2016-02-20 17:32:51 -05:00
parent 68992a62f9
commit 00f414d757
4 changed files with 56 additions and 254 deletions

View File

@ -394,6 +394,16 @@ inline void Machine::output_pixels(int start_x, int number_of_pixels)
{
if(number_of_pixels)
{
if(
((_screen_mode == 3) || (_screen_mode == 6)) &&
(((display_y%10) >= 8) || (display_y >= 250))
)
{
end_pixel_output();
_crt->output_blank((unsigned int)number_of_pixels * crt_cycles_multiplier);
return;
}
unsigned int newDivider = 0;
switch(_screen_mode)
{
@ -512,11 +522,6 @@ inline void Machine::update_pixels_to_position(int x, int y)
if(display_x == last_graphics_cycle)
{
end_pixel_output();
// if(_crt->get_field_cycle() - end != 640)
// {
// printf("!!!\n");
// }
}
continue;
}
@ -528,95 +533,44 @@ inline void Machine::update_pixels_to_position(int x, int y)
display_x = 0;
display_y++;
_startLineAddress++;
_currentOutputLine++;
if(_currentOutputLine == 8)
if(((_screen_mode != 3) && (_screen_mode != 6)) || ((display_y%10) < 8))
{
_currentOutputLine = 0;
_startLineAddress = _currentScreenAddress - 7;
_startLineAddress++;
_currentOutputLine++;
if(_currentOutputLine == 8)
{
_currentOutputLine = 0;
_startLineAddress = (_startLineAddress - 8) + ((_screen_mode < 4) ? 80 : 40)*8;
}
}
}
}
/* while(_displayOutputPosition < end_of_graphics && _displayOutputPosition)
{
int displayOffset = _displayOutputPosition - end_of_graphics;
int cyclesRemaining = _fieldCycles - _displayOutputPosition;
// int current_line = displayOffset >> 7;
int current_pixel = displayOffset & 127;
if(current_pixel < 9)
{
if(cyclesRemaining > 9)
{
_crt->output_sync(9 * crt_cycles_multiplier);
cyclesRemaining -= 9;
_displayOutputPosition += 9;
}
else return;
}
int line_remainder = std::min(119, cyclesRemaining);
_crt->output_blank((unsigned int)line_remainder * crt_cycles_multiplier);
_displayOutputPosition += line_remainder;
current_pixel += line_remainder;
if(current_pixel < 128) return;
}*/
}
inline void Machine::update_display()
{
/*
Odd field:
Odd field: Even field:
|--S--|
|--S--|
|-S-B-|
|--B--|
|--P--|
|--B--|
(2.5 lines of sync; half a line of blank; full blanks; pixels; full blanks; half blank)
Even field:
|-B-S-|
|--S--|
|--S--|
|--B--|
|--P--|
|--B--|
(2.5 lines of sync; full blanks; pixels; full blanks)
So:
Top:
if even then half a line of blank
2.5 lines of sync
if odd then half a line of blank
full blanks
Pixels
Bottom:
full blanks
|--S--| -S-|
|--S--| |--S--|
|-S-B-| = 3 |--S--| = 2.5
|--B--| |--B--|
|--P--| |--P--|
|--B--| = 312 |--B--| = 312.5
|-B-
*/
const int end_of_top = (first_graphics_line * cycles_per_line) + (_is_odd_field ? 64 : 0);
const int end_of_graphics = ((first_graphics_line + 256) * cycles_per_line) + (_is_odd_field ? 64 : 0);
const unsigned int end_of_top = (first_graphics_line * cycles_per_line) + (_is_odd_field ? 64 : 0);
const unsigned int end_of_graphics = end_of_top + 256 * cycles_per_line;
// does the top region need to be output?
if(_displayOutputPosition < end_of_top && _fieldCycles >= end_of_top)
{
// printf("[1] %d / %d\n", _crt->get_field_cycle() >> 10, (_crt->get_field_cycle() >> 3)&127);
if(!_is_odd_field)
{
_crt->output_sync(9 * crt_cycles_multiplier);
_crt->output_blank(55 * crt_cycles_multiplier);
}
_crt->output_sync(320 * crt_cycles_multiplier);
if(_is_odd_field) _crt->output_blank(64 * crt_cycles_multiplier);
@ -625,7 +579,6 @@ inline void Machine::update_display()
_crt->output_sync(9 * crt_cycles_multiplier);
_crt->output_blank(119 * crt_cycles_multiplier);
}
// printf("[2] %d / %d\n", _crt->get_field_cycle() >> 10, (_crt->get_field_cycle() >> 3)&127);
_displayOutputPosition = end_of_top;
@ -635,197 +588,34 @@ inline void Machine::update_display()
// is this the pixel region?
if(_displayOutputPosition >= end_of_top && _displayOutputPosition < end_of_graphics)
{
int final_position = std::min(_fieldCycles, end_of_top + 256 * 128) - end_of_top;
int final_line = final_position >> 7;
int final_pixel = final_position & 127;
update_pixels_to_position(final_pixel, final_line);
unsigned int final_position = std::min(_fieldCycles, end_of_graphics) - end_of_top;
unsigned int final_line = final_position >> 7;
unsigned int final_pixel = final_position & 127;
update_pixels_to_position((int)final_pixel, (int)final_line);
_displayOutputPosition = final_position + end_of_top;
}
// is this the bottom region?
if(_displayOutputPosition >= end_of_graphics && _displayOutputPosition < cycles_per_frame)
{
// printf("[3] %d / %d\n", _crt->get_field_cycle() >> 10, (_crt->get_field_cycle() >> 3)&127);
for(int y = first_graphics_line+256; y < 312; y++)
unsigned int remaining_time = cycles_per_frame - _displayOutputPosition;
while(remaining_time >= 128)
{
_crt->output_sync(9 * crt_cycles_multiplier);
_crt->output_blank(119 * crt_cycles_multiplier);
remaining_time -= 128;
}
_displayOutputPosition = cycles_per_frame;
// printf("[4] %d / %d\n", _crt->get_field_cycle() >> 10, (_crt->get_field_cycle() >> 3)&127);
_is_odd_field ^= true;
}
// no? Then let's do some pixels
/* if(_fieldCycles >= end_of_hsync)
{
// assert sync for the first three lines of the display, with a break at the end for horizontal alignment
if(_displayOutputPosition < end_of_hsync)
if(remaining_time == 64)
{
_crt->output_sync(9 * crt_cycles_multiplier);
_crt->output_blank(55 * crt_cycles_multiplier);
_crt->output_sync(320 * crt_cycles_multiplier);
_is_odd_field ^= true;
_displayOutputPosition = end_of_hsync;
}
while(_displayOutputPosition >= end_of_hsync && _displayOutputPosition < _fieldCycles)
{
const int cycles_left = _fieldCycles - _displayOutputPosition;
_displayOutputPosition = cycles_per_frame;
const int fieldOutputPosition = get_line_output_position(_displayOutputPosition);
const int current_line = fieldOutputPosition >> 7;
const int line_position = fieldOutputPosition & 127;
// all lines then start with 9 cycles of sync
if(line_position < 9)
{
int remaining_period = std::min(9 - line_position, cycles_left);
_displayOutputPosition += remaining_period;
if(line_position + remaining_period == 9)
{
_crt->output_sync(9 * crt_cycles_multiplier);
}
}
else
{
bool isBlankLine =
(current_line < first_graphics_line) ||
(((_screen_mode == 3) || (_screen_mode == 6)) ?
((current_line >= first_graphics_line+248) || (((current_line - first_graphics_line)%10) > 7)) :
((current_line >= first_graphics_line+256)));
bool isBlankPeriod =
(line_position < first_graphics_cycle) || (line_position >= 80+first_graphics_cycle);
if(isBlankLine || isBlankPeriod)
{
if(_currentLine)
{
_crt->output_data((unsigned int)((_writePointer - _currentLine) * _currentOutputDivider * crt_cycles_multiplier), _currentOutputDivider);
_currentLine = _writePointer = nullptr;
}
int target = (isBlankLine || (line_position > first_graphics_cycle)) ? 128 : first_graphics_cycle;
int remaining_period = std::min(target - line_position, cycles_left);
_crt->output_blank((unsigned int)remaining_period * crt_cycles_multiplier);
_displayOutputPosition += remaining_period;
if(line_position + remaining_period == 128)
{
_currentOutputLine++;
if(!(_currentOutputLine&7))
{
_startLineAddress += ((_screen_mode < 4) ? 80 : 40)*8 - 7;
}
else
_startLineAddress++;
}
}
else
{
if(line_position == first_graphics_cycle)
{
if(current_line == first_graphics_line) _startLineAddress = _startScreenAddress;
_currentScreenAddress = _startLineAddress;
}
// determine the pixel clock
unsigned int newDivider = 0;
switch(_screen_mode)
{
case 0: case 3: newDivider = 1; break;
case 1: case 4: case 6: newDivider = 2; break;
case 2: case 5: newDivider = 4; break;
}
// if the clock has changed or we don't yet have a write pointer, get one
if((newDivider != _currentOutputDivider) || !_currentLine)
{
if(_currentLine)
{
_crt->output_data((unsigned int)((_writePointer - _currentLine) * _currentOutputDivider * crt_cycles_multiplier), _currentOutputDivider);
}
_currentOutputDivider = newDivider;
_crt->allocate_write_area((size_t)((80 + first_graphics_cycle - (unsigned int)line_position) * crt_cycles_multiplier / _currentOutputDivider));
_currentLine = _writePointer = (uint8_t *)_crt->get_write_target_for_buffer(0);
}
// determine how many pixels to write
int pixels_to_output = std::min(80 + first_graphics_cycle - line_position, cycles_left);
_displayOutputPosition += pixels_to_output;
if(_screen_mode >= 4)
{
if(_displayOutputPosition&1) pixels_to_output++;
pixels_to_output >>= 1;
}
#define GetNextPixels() \
if(_currentScreenAddress&32768)\
{\
_currentScreenAddress = (_screenModeBaseAddress + _currentScreenAddress)&32767;\
}\
uint8_t pixels = _ram[_currentScreenAddress];\
_currentScreenAddress = _currentScreenAddress+8
if(pixels_to_output)
{
switch(_screen_mode)
{
default:
case 0: case 3: case 4: case 6:
while(pixels_to_output--)
{
GetNextPixels();
_writePointer[0] = _palette[(pixels&0x80) >> 4];
_writePointer[1] = _palette[(pixels&0x40) >> 3];
_writePointer[2] = _palette[(pixels&0x20) >> 2];
_writePointer[3] = _palette[(pixels&0x10) >> 1];
_writePointer[4] = _palette[(pixels&0x08) >> 0];
_writePointer[5] = _palette[(pixels&0x04) << 1];
_writePointer[6] = _palette[(pixels&0x02) << 2];
_writePointer[7] = _palette[(pixels&0x01) << 3];
_writePointer += 8;
}
break;
case 1:
case 5:
while(pixels_to_output--)
{
GetNextPixels();
_writePointer[0] = _palette[((pixels&0x80) >> 4) | ((pixels&0x08) >> 2)];
_writePointer[1] = _palette[((pixels&0x40) >> 3) | ((pixels&0x04) >> 1)];
_writePointer[2] = _palette[((pixels&0x20) >> 2) | ((pixels&0x02) >> 0)];
_writePointer[3] = _palette[((pixels&0x10) >> 1) | ((pixels&0x01) << 1)];
_writePointer += 4;
}
break;
case 2:
while(pixels_to_output--)
{
GetNextPixels();
_writePointer[0] = _palette[((pixels&0x80) >> 4) | ((pixels&0x20) >> 3) | ((pixels&0x08) >> 2) | ((pixels&0x02) >> 1)];
_writePointer[1] = _palette[((pixels&0x40) >> 3) | ((pixels&0x10) >> 2) | ((pixels&0x04) >> 1) | ((pixels&0x01) >> 0)];
_writePointer += 2;
}
break;
}
}
#undef GetNextPixels
}
}
}
}*/
_is_odd_field ^= true;
}
}
void Machine::set_key_state(Key key, bool isPressed)

View File

@ -183,7 +183,7 @@ class Machine: public CPU6502::Processor<Machine>, Tape::Delegate {
uint16_t _startScreenAddress;
// Counters related to simultaneous subsystems;
int _fieldCycles, _displayOutputPosition;
unsigned int _fieldCycles, _displayOutputPosition;
int _audioOutputPosition, _audioOutputPositionError;
// Display generation.

View File

@ -219,6 +219,16 @@ class CRT {
{
return _run_builders[_run_write_pointer]->duration / _time_multiplier;
}
inline uint32_t get_line_cycle()
{
return _horizontal_flywheel->get_current_time() / _time_multiplier;
}
inline float get_raster_x()
{
return (float)_horizontal_flywheel->get_current_output_position() / (float)_horizontal_flywheel->get_scan_period();
}
#endif
private:

View File

@ -73,11 +73,13 @@ struct Flywheel
if(_counter < _retrace_time + (_expected_next_sync >> 1))
{
_expected_next_sync++;
_expected_next_sync = (_expected_next_sync + _standard_period + _sync_error_window) >> 1;
// _expected_next_sync+=;
}
else
{
_expected_next_sync--;
_expected_next_sync = (_expected_next_sync + _standard_period - _sync_error_window) >> 1;
// _expected_next_sync--;
}
}
}