mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-26 09:29:45 +00:00
An early draft; dealing with the issue that not all cycles are necessarily consumed in a single call. Incomplete; broken. Committing for cross-machine visibility.
This commit is contained in:
parent
be7e05e109
commit
fd541e1142
@ -344,12 +344,13 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target)
|
|||||||
|
|
||||||
if(target.loadingCommand.length()) // TODO: and automatic loading option enabled
|
if(target.loadingCommand.length()) // TODO: and automatic loading option enabled
|
||||||
{
|
{
|
||||||
set_typer_for_string(target.loadingCommand.c_str());
|
// set_typer_for_string(target.loadingCommand.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(target.acorn.should_hold_shift)
|
if(target.acorn.should_hold_shift)
|
||||||
{
|
{
|
||||||
set_key_state(KeyShift, true);
|
// set_key_state(KeyShift, true);
|
||||||
is_holding_shift_ = true;
|
// is_holding_shift_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,8 +405,11 @@ inline void Machine::evaluate_interrupts()
|
|||||||
|
|
||||||
inline void Machine::update_display()
|
inline void Machine::update_display()
|
||||||
{
|
{
|
||||||
video_output_->run_for_cycles((int)cycles_since_display_update_);
|
if(cycles_since_display_update_)
|
||||||
cycles_since_display_update_ = 0;
|
{
|
||||||
|
video_output_->run_for_cycles((int)cycles_since_display_update_);
|
||||||
|
cycles_since_display_update_ = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Machine::queue_next_display_interrupt()
|
inline void Machine::queue_next_display_interrupt()
|
||||||
@ -417,9 +421,12 @@ inline void Machine::queue_next_display_interrupt()
|
|||||||
|
|
||||||
inline void Machine::update_audio()
|
inline void Machine::update_audio()
|
||||||
{
|
{
|
||||||
unsigned int difference = cycles_since_audio_update_ / Speaker::clock_rate_divider;
|
if(cycles_since_audio_update_)
|
||||||
cycles_since_audio_update_ %= Speaker::clock_rate_divider;
|
{
|
||||||
speaker_->run_for_cycles(difference);
|
unsigned int difference = cycles_since_audio_update_ / Speaker::clock_rate_divider;
|
||||||
|
cycles_since_audio_update_ %= Speaker::clock_rate_divider;
|
||||||
|
speaker_->run_for_cycles(difference);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::clear_all_keys()
|
void Machine::clear_all_keys()
|
||||||
|
@ -14,17 +14,17 @@ using namespace Electron;
|
|||||||
#define graphics_column(v) ((((v) & 127) - first_graphics_cycle + 128) & 127)
|
#define graphics_column(v) ((((v) & 127) - first_graphics_cycle + 128) & 127)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static const unsigned int cycles_per_line = 128;
|
static const int cycles_per_line = 128;
|
||||||
static const unsigned int lines_per_frame = 625;
|
static const int lines_per_frame = 625;
|
||||||
static const int cycles_per_frame = lines_per_frame * cycles_per_line;
|
static const int cycles_per_frame = lines_per_frame * cycles_per_line;
|
||||||
static const unsigned int crt_cycles_multiplier = 8;
|
static const int crt_cycles_multiplier = 8;
|
||||||
static const unsigned int crt_cycles_per_line = crt_cycles_multiplier * cycles_per_line;
|
static const int crt_cycles_per_line = crt_cycles_multiplier * cycles_per_line;
|
||||||
|
|
||||||
static const unsigned int field_divider_line = 312; // i.e. the line, simultaneous with which, the first field's sync ends. So if
|
static const int field_divider_line = 312; // i.e. the line, simultaneous with which, the first field's sync ends. So if
|
||||||
// the first line with pixels in field 1 is the 20th in the frame, the first line
|
// the first line with pixels in field 1 is the 20th in the frame, the first line
|
||||||
// with pixels in field 2 will be 20+field_divider_line
|
// with pixels in field 2 will be 20+field_divider_line
|
||||||
static const unsigned int first_graphics_line = 31;
|
static const int first_graphics_line = 31;
|
||||||
static const unsigned int first_graphics_cycle = 33;
|
static const int first_graphics_cycle = 33;
|
||||||
|
|
||||||
static const int display_end_interrupt_line = 256;
|
static const int display_end_interrupt_line = 256;
|
||||||
|
|
||||||
@ -244,6 +244,134 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoOutput::run_for_inner_frame_cycles(int number_of_cycles)
|
||||||
|
{
|
||||||
|
int target_output_position = output_position_ + number_of_cycles;
|
||||||
|
int final_line = target_output_position >> 7;
|
||||||
|
|
||||||
|
while(output_position_ < target_output_position)
|
||||||
|
{
|
||||||
|
int line = output_position_ >> 7;
|
||||||
|
|
||||||
|
// Priority one: sync.
|
||||||
|
// ===================
|
||||||
|
|
||||||
|
// full sync lines are 0, 1, field_divider_line+1 and field_divider_line+2
|
||||||
|
if(line == 0 || line == 1 || line == field_divider_line+1 || line == field_divider_line+2)
|
||||||
|
{
|
||||||
|
// wait for the line to complete before signalling
|
||||||
|
if(final_line == line) return;
|
||||||
|
crt_->output_sync(128 * crt_cycles_multiplier);
|
||||||
|
output_position_ += 128;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// line 2 is a left-sync line
|
||||||
|
if(line == 2)
|
||||||
|
{
|
||||||
|
// wait for the line to complete before signalling
|
||||||
|
if(final_line == line) return;
|
||||||
|
crt_->output_sync(64 * crt_cycles_multiplier);
|
||||||
|
crt_->output_blank(64 * crt_cycles_multiplier);
|
||||||
|
output_position_ += 128;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// line field_divider_line is a right-sync line
|
||||||
|
if(line == field_divider_line)
|
||||||
|
{
|
||||||
|
// wait for the line to complete before signalling
|
||||||
|
if(final_line == line) return;
|
||||||
|
crt_->output_sync(9 * crt_cycles_multiplier);
|
||||||
|
crt_->output_blank(55 * crt_cycles_multiplier);
|
||||||
|
crt_->output_sync(64 * crt_cycles_multiplier);
|
||||||
|
output_position_ += 128;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority two: blank lines.
|
||||||
|
// ==========================
|
||||||
|
//
|
||||||
|
// Given that it is not a sync line, this is a blank line if it is less than first_graphics_line, or greater
|
||||||
|
// than first_graphics_line+255 and less than first_graphics_line+field_divider_line, or greater than
|
||||||
|
// first_graphics_line+field_divider_line+255 (TODO: or this is Mode 3 or 6 and this should be blank)
|
||||||
|
if(
|
||||||
|
line < first_graphics_line ||
|
||||||
|
(line > first_graphics_line+255 && line < first_graphics_line+field_divider_line) ||
|
||||||
|
line > first_graphics_line+field_divider_line+255)
|
||||||
|
{
|
||||||
|
if(final_line == line) return;
|
||||||
|
crt_->output_sync(9 * crt_cycles_multiplier);
|
||||||
|
crt_->output_blank(119 * crt_cycles_multiplier);
|
||||||
|
output_position_ += 128;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final possibility: this is a pixel line.
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// determine how far we're going from left to right
|
||||||
|
int this_cycle = output_position_&127;
|
||||||
|
int final_cycle = target_output_position&127;
|
||||||
|
if(final_line > line)
|
||||||
|
{
|
||||||
|
final_cycle = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
// output format is:
|
||||||
|
// 9 cycles: sync
|
||||||
|
// ... to 24 cycles: colour burst
|
||||||
|
// ... to first_graphics_cycle: blank
|
||||||
|
// ... for 80 cycles: pixels
|
||||||
|
// ... until end of line: blank
|
||||||
|
while(this_cycle < final_cycle)
|
||||||
|
{
|
||||||
|
if(this_cycle < 9)
|
||||||
|
{
|
||||||
|
if(final_cycle < 9) return;
|
||||||
|
crt_->output_sync(9 * crt_cycles_multiplier);
|
||||||
|
output_position_ += 9;
|
||||||
|
this_cycle = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this_cycle < 24)
|
||||||
|
{
|
||||||
|
if(final_cycle < 24) return;
|
||||||
|
crt_->output_default_colour_burst((24-9) * crt_cycles_multiplier);
|
||||||
|
output_position_ += 24-9;
|
||||||
|
this_cycle = 24;
|
||||||
|
// TODO: phase shouldn't be zero on every line
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this_cycle < first_graphics_cycle)
|
||||||
|
{
|
||||||
|
if(final_cycle < first_graphics_cycle) return;
|
||||||
|
crt_->output_blank((first_graphics_cycle - 24) * crt_cycles_multiplier);
|
||||||
|
output_position_ += first_graphics_cycle - 24;
|
||||||
|
this_cycle = first_graphics_cycle;
|
||||||
|
start_pixel_line();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this_cycle < first_graphics_cycle + 80)
|
||||||
|
{
|
||||||
|
unsigned int length_to_output = std::min(final_cycle, (first_graphics_cycle + 80)) - this_cycle;
|
||||||
|
output_pixels(length_to_output);
|
||||||
|
output_position_ += length_to_output;
|
||||||
|
this_cycle += length_to_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this_cycle >= first_graphics_cycle + 80)
|
||||||
|
{
|
||||||
|
if(final_cycle < 128) return;
|
||||||
|
end_pixel_line();
|
||||||
|
crt_->output_blank((128 - (first_graphics_cycle + 80)) * crt_cycles_multiplier);
|
||||||
|
output_position_ += 128 - (first_graphics_cycle + 80);
|
||||||
|
this_cycle = 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VideoOutput::run_for_cycles(int number_of_cycles)
|
void VideoOutput::run_for_cycles(int number_of_cycles)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -259,136 +387,18 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
|||||||
|-B-
|
|-B-
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int final_position = output_position_ + number_of_cycles;
|
int cycles_at_end = unused_cycles_ + output_position_ + number_of_cycles;
|
||||||
|
unused_cycles_ = 0;
|
||||||
int number_of_frames = 1 + (final_position / cycles_per_frame);
|
|
||||||
|
|
||||||
|
int number_of_frames = 1 + (cycles_at_end / cycles_per_frame);
|
||||||
while(number_of_frames--)
|
while(number_of_frames--)
|
||||||
{
|
{
|
||||||
int frame_final = number_of_frames ? cycles_per_frame : (final_position % cycles_per_frame);
|
int frame_target = number_of_frames ? cycles_per_frame : (cycles_at_end % cycles_per_frame);
|
||||||
int final_line = frame_final >> 7;
|
run_for_inner_frame_cycles(frame_target - output_position_);
|
||||||
|
// unused_cycles_ += (frame_final - output_position_);
|
||||||
while(output_position_ < frame_final)
|
// if(unused_cycles_)
|
||||||
{
|
// {
|
||||||
int line = output_position_ >> 7;
|
// }
|
||||||
|
|
||||||
// Priority one: sync.
|
|
||||||
// ===================
|
|
||||||
|
|
||||||
// full sync lines are 0, 1, field_divider_line+1 and field_divider_line+2
|
|
||||||
if(line == 0 || line == 1 || line == field_divider_line+1 || line == field_divider_line+2)
|
|
||||||
{
|
|
||||||
// wait for the line to complete before signalling
|
|
||||||
if(final_line == line) return;
|
|
||||||
crt_->output_sync(128 * crt_cycles_multiplier);
|
|
||||||
output_position_ += 128;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// line 2 is a left-sync line
|
|
||||||
if(line == 2)
|
|
||||||
{
|
|
||||||
// wait for the line to complete before signalling
|
|
||||||
if(final_line == line) return;
|
|
||||||
crt_->output_sync(64 * crt_cycles_multiplier);
|
|
||||||
crt_->output_blank(64 * crt_cycles_multiplier);
|
|
||||||
output_position_ += 128;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// line field_divider_line is a right-sync line
|
|
||||||
if(line == field_divider_line)
|
|
||||||
{
|
|
||||||
// wait for the line to complete before signalling
|
|
||||||
if(final_line == line) return;
|
|
||||||
crt_->output_sync(9 * crt_cycles_multiplier);
|
|
||||||
crt_->output_blank(55 * crt_cycles_multiplier);
|
|
||||||
crt_->output_sync(64 * crt_cycles_multiplier);
|
|
||||||
output_position_ += 128;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Priority two: blank lines.
|
|
||||||
// ==========================
|
|
||||||
//
|
|
||||||
// Given that it is not a sync line, this is a blank line if it is less than first_graphics_line, or greater
|
|
||||||
// than first_graphics_line+255 and less than first_graphics_line+field_divider_line, or greater than
|
|
||||||
// first_graphics_line+field_divider_line+255 (TODO: or this is Mode 3 or 6 and this should be blank)
|
|
||||||
if(
|
|
||||||
line < first_graphics_line ||
|
|
||||||
(line > first_graphics_line+255 && line < first_graphics_line+field_divider_line) ||
|
|
||||||
line > first_graphics_line+field_divider_line+255)
|
|
||||||
{
|
|
||||||
if(final_line == line) return;
|
|
||||||
crt_->output_sync(9 * crt_cycles_multiplier);
|
|
||||||
crt_->output_blank(119 * crt_cycles_multiplier);
|
|
||||||
output_position_ += 128;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final possibility: this is a pixel line.
|
|
||||||
// ========================================
|
|
||||||
|
|
||||||
// determine how far we're going from left to right
|
|
||||||
unsigned int this_cycle = output_position_&127;
|
|
||||||
unsigned int final_cycle = frame_final&127;
|
|
||||||
if(final_line > line)
|
|
||||||
{
|
|
||||||
final_cycle = 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
// output format is:
|
|
||||||
// 9 cycles: sync
|
|
||||||
// ... to 24 cycles: colour burst
|
|
||||||
// ... to first_graphics_cycle: blank
|
|
||||||
// ... for 80 cycles: pixels
|
|
||||||
// ... until end of line: blank
|
|
||||||
while(this_cycle < final_cycle)
|
|
||||||
{
|
|
||||||
if(this_cycle < 9)
|
|
||||||
{
|
|
||||||
if(final_cycle < 9) return;
|
|
||||||
crt_->output_sync(9 * crt_cycles_multiplier);
|
|
||||||
output_position_ += 9;
|
|
||||||
this_cycle = 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this_cycle < 24)
|
|
||||||
{
|
|
||||||
if(final_cycle < 24) return;
|
|
||||||
crt_->output_default_colour_burst((24-9) * crt_cycles_multiplier);
|
|
||||||
output_position_ += 24-9;
|
|
||||||
this_cycle = 24;
|
|
||||||
// TODO: phase shouldn't be zero on every line
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this_cycle < first_graphics_cycle)
|
|
||||||
{
|
|
||||||
if(final_cycle < first_graphics_cycle) return;
|
|
||||||
crt_->output_blank((first_graphics_cycle - 24) * crt_cycles_multiplier);
|
|
||||||
output_position_ += first_graphics_cycle - 24;
|
|
||||||
this_cycle = first_graphics_cycle;
|
|
||||||
start_pixel_line();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this_cycle < first_graphics_cycle + 80)
|
|
||||||
{
|
|
||||||
unsigned int length_to_output = std::min(final_cycle, (first_graphics_cycle + 80)) - this_cycle;
|
|
||||||
output_pixels(length_to_output);
|
|
||||||
output_position_ += length_to_output;
|
|
||||||
this_cycle += length_to_output;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this_cycle >= first_graphics_cycle + 80)
|
|
||||||
{
|
|
||||||
if(final_cycle < 128) return;
|
|
||||||
end_pixel_line();
|
|
||||||
crt_->output_blank((128 - (first_graphics_cycle + 80)) * crt_cycles_multiplier);
|
|
||||||
output_position_ += 128 - (first_graphics_cycle + 80);
|
|
||||||
this_cycle = 128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output_position_ %= cycles_per_frame;
|
output_position_ %= cycles_per_frame;
|
||||||
}
|
}
|
||||||
@ -575,16 +585,18 @@ VideoOutput::Interrupt VideoOutput::get_next_interrupt()
|
|||||||
|
|
||||||
#pragma mark - RAM timing
|
#pragma mark - RAM timing
|
||||||
|
|
||||||
unsigned int VideoOutput::get_cycles_until_next_ram_availability(unsigned int from_time)
|
unsigned int VideoOutput::get_cycles_until_next_ram_availability(int from_time)
|
||||||
{
|
{
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
// cycles += 1 + (frame_cycles_&1);
|
int position = output_position_ + from_time;
|
||||||
|
|
||||||
|
result += 1 + (position&1);
|
||||||
// if(screen_mode_ < 4)
|
// if(screen_mode_ < 4)
|
||||||
// {
|
// {
|
||||||
// const int current_line = graphics_line(frame_cycles_ + (frame_cycles_&1));
|
// const int current_line = graphics_line(position + (position&1));
|
||||||
// const int current_column = graphics_column(frame_cycles_ + (frame_cycles_&1));
|
// const int current_column = graphics_column(position + (position&1));
|
||||||
// if(current_line < 256 && current_column < 80 && !is_blank_line_)
|
// if(current_line < 256 && current_column < 80 && !is_blank_line_)
|
||||||
// cycles += (unsigned int)(80 - current_column);
|
// result += (unsigned int)(80 - current_column);
|
||||||
// }
|
// }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,16 @@ class VideoOutput {
|
|||||||
|
|
||||||
void set_register(int address, uint8_t value);
|
void set_register(int address, uint8_t value);
|
||||||
|
|
||||||
unsigned int get_cycles_until_next_ram_availability(unsigned int from_time);
|
unsigned int get_cycles_until_next_ram_availability(int from_time);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void start_pixel_line();
|
inline void start_pixel_line();
|
||||||
inline void end_pixel_line();
|
inline void end_pixel_line();
|
||||||
inline void output_pixels(unsigned int number_of_cycles);
|
inline void output_pixels(unsigned int number_of_cycles);
|
||||||
|
|
||||||
int output_position_;
|
inline void run_for_inner_frame_cycles(int number_of_cycles);
|
||||||
|
|
||||||
|
int output_position_, unused_cycles_;
|
||||||
|
|
||||||
uint8_t palette_[16];
|
uint8_t palette_[16];
|
||||||
uint8_t screen_mode_;
|
uint8_t screen_mode_;
|
||||||
|
Loading…
Reference in New Issue
Block a user