1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-10-15 20:24:07 +00:00

Merge pull request #65 from TomHarte/OricVideoImprovements

Rearranges Oric painting logic to reduce code path complexity
This commit is contained in:
Thomas Harte 2016-10-30 20:17:24 -04:00 committed by GitHub
commit 9f66f6abfe
2 changed files with 146 additions and 115 deletions

View File

@ -22,7 +22,6 @@ namespace {
VideoOutput::VideoOutput(uint8_t *memory) : VideoOutput::VideoOutput(uint8_t *memory) :
_ram(memory), _ram(memory),
_frame_counter(0), _counter(0), _frame_counter(0), _counter(0),
_state(Sync), _cycles_in_state(0),
_is_graphics_mode(false), _is_graphics_mode(false),
_character_set_base_address(0xb400), _character_set_base_address(0xb400),
_phase(0), _phase(0),
@ -54,11 +53,23 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
// Vertical: 039: pixels; otherwise blank; 4853 sync, 5456 colour burst // Vertical: 039: pixels; otherwise blank; 4853 sync, 5456 colour burst
// Horizontal: 0223: pixels; otherwise blank; 256259 sync // Horizontal: 0223: pixels; otherwise blank; 256259 sync
while(number_of_cycles--) #define clamp(action) \
{ if(cycles_run_for <= number_of_cycles) { action; } else cycles_run_for = number_of_cycles;
_counter = (_counter + 1)%_counter_period;
int h_counter =_counter & 63;
while(number_of_cycles)
{
int h_counter =_counter & 63;
int cycles_run_for = 0;
if(_counter >= _v_sync_start_position && _counter < _v_sync_end_position)
{
// this is a sync line
cycles_run_for = _v_sync_end_position - _counter;
clamp(_crt->output_sync((unsigned int)(_v_sync_end_position - _v_sync_start_position) * 6));
}
else if(_counter < 224*64 && h_counter < 40)
{
// this is a pixel line
if(!h_counter) if(!h_counter)
{ {
_ink = 0xff; _ink = 0xff;
@ -66,10 +77,11 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
_use_alternative_character_set = _use_double_height_characters = _blink_text = false; _use_alternative_character_set = _use_double_height_characters = _blink_text = false;
set_character_set_base_address(); set_character_set_base_address();
_phase += 64; _phase += 64;
_pixel_target = _crt->allocate_write_area(120);
if(!_counter) if(!_counter)
{ {
_phase += 128; _phase += 128; // TODO: incorporate all the lines that were missed
_frame_counter++; _frame_counter++;
_v_sync_start_position = _next_frame_is_sixty_hertz ? PAL60VSyncStartPosition : PAL50VSyncStartPosition; _v_sync_start_position = _next_frame_is_sixty_hertz ? PAL60VSyncStartPosition : PAL50VSyncStartPosition;
@ -78,46 +90,30 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
} }
} }
cycles_run_for = std::min(40 - h_counter, number_of_cycles);
int columns = cycles_run_for;
int pixel_base_address = 0xa000 + (_counter >> 6) * 40;
int character_base_address = 0xbb80 + (_counter >> 9) * 40;
uint8_t blink_mask = (_blink_text && (_frame_counter&32)) ? 0x00 : 0xff;
State new_state = Blank; while(columns--)
if(
(h_counter >= 48 && h_counter <= 53) ||
(_counter >= _v_sync_start_position && _counter <= _v_sync_end_position)) new_state = Sync;
else if(h_counter >= 54 && h_counter <= 56) new_state = ColourBurst;
else if(_counter < 224*64 && h_counter < 40) new_state = Pixels;
if(_state != new_state)
{ {
switch(_state)
{
case ColourBurst: _crt->output_colour_burst(_cycles_in_state * 6, _phase, 128); break;
case Sync: _crt->output_sync(_cycles_in_state * 6); break;
case Blank: _crt->output_blank(_cycles_in_state * 6); break;
case Pixels: _crt->output_data(_cycles_in_state * 6, 2); break;
}
_state = new_state;
_cycles_in_state = 0;
if(_state == Pixels) _pixel_target = _crt->allocate_write_area(120);
}
_cycles_in_state++;
if(new_state == Pixels) {
uint8_t pixels, control_byte; uint8_t pixels, control_byte;
if(_is_graphics_mode && _counter < 200*64) if(_is_graphics_mode && _counter < 200*64)
{ {
control_byte = pixels = _ram[0xa000 + (_counter >> 6) * 40 + h_counter]; control_byte = pixels = _ram[pixel_base_address + h_counter];
} }
else else
{ {
int address = 0xbb80 + (_counter >> 9) * 40 + h_counter; int address = character_base_address + h_counter;
control_byte = _ram[address]; control_byte = _ram[address];
int line = _use_double_height_characters ? ((_counter >> 7) & 7) : ((_counter >> 6) & 7); int line = _use_double_height_characters ? ((_counter >> 7) & 7) : ((_counter >> 6) & 7);
pixels = _ram[_character_set_base_address + (control_byte&127) * 8 + line]; pixels = _ram[_character_set_base_address + (control_byte&127) * 8 + line];
} }
uint8_t inverse_mask = (control_byte & 0x80) ? 0x77 : 0x00; uint8_t inverse_mask = (control_byte & 0x80) ? 0x77 : 0x00;
if(_blink_text && (_frame_counter&32)) pixels = 0; pixels &= blink_mask;
if(control_byte & 0x60) if(control_byte & 0x60)
{ {
@ -174,6 +170,49 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
if(_pixel_target) _pixel_target[0] = _pixel_target[1] = _pixel_target[2] = (uint8_t)(_paper ^ inverse_mask); if(_pixel_target) _pixel_target[0] = _pixel_target[1] = _pixel_target[2] = (uint8_t)(_paper ^ inverse_mask);
} }
if(_pixel_target) _pixel_target += 3; if(_pixel_target) _pixel_target += 3;
h_counter++;
} }
if(h_counter == 40)
{
_crt->output_data(40 * 6, 2);
}
}
else
{
// this is a blank line (or the equivalent part of a pixel line)
if(h_counter < 48)
{
cycles_run_for = 48 - h_counter;
clamp(
int period = (_counter < 224*64) ? 8 : 48;
_crt->output_blank((unsigned int)period * 6);
);
}
else if(h_counter < 54)
{
cycles_run_for = 54 - h_counter;
clamp(_crt->output_sync(6 * 6));
}
else if(h_counter < 56)
{
cycles_run_for = 56 - h_counter;
clamp(_crt->output_colour_burst(2 * 6, _phase, 128));
}
else
{
cycles_run_for = 64 - h_counter;
clamp(_crt->output_blank(8 * 6));
}
}
_counter = (_counter + cycles_run_for)%_counter_period;
number_of_cycles -= cycles_run_for;
} }
} }
void VideoOutput::set_character_set_base_address()
{
if(_is_graphics_mode) _character_set_base_address = _use_alternative_character_set ? 0x9c00 : 0x9800;
else _character_set_base_address = _use_alternative_character_set ? 0xb800 : 0xb400;
}

View File

@ -27,22 +27,14 @@ class VideoOutput {
int _counter, _frame_counter; int _counter, _frame_counter;
int _v_sync_start_position, _v_sync_end_position, _counter_period; int _v_sync_start_position, _v_sync_end_position, _counter_period;
// Output state // Output target
enum State {
Blank, Sync, Pixels, ColourBurst
} _state;
unsigned int _cycles_in_state;
uint8_t *_pixel_target; uint8_t *_pixel_target;
// Registers // Registers
uint8_t _ink, _paper; uint8_t _ink, _paper;
int _character_set_base_address; int _character_set_base_address;
inline void set_character_set_base_address() inline void set_character_set_base_address();
{
if(_is_graphics_mode) _character_set_base_address = _use_alternative_character_set ? 0x9c00 : 0x9800;
else _character_set_base_address = _use_alternative_character_set ? 0xb800 : 0xb400;
}
bool _is_graphics_mode; bool _is_graphics_mode;
bool _next_frame_is_sixty_hertz; bool _next_frame_is_sixty_hertz;