mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 01:31:42 +00:00
Merge branch 'master' into DiskWrites
This commit is contained in:
commit
54b5056c74
@ -60,7 +60,7 @@ Machine::Machine() :
|
|||||||
void Machine::setup_output(float aspect_ratio)
|
void Machine::setup_output(float aspect_ratio)
|
||||||
{
|
{
|
||||||
speaker_.reset(new Speaker);
|
speaker_.reset(new Speaker);
|
||||||
crt_.reset(new Outputs::CRT::CRT(228, 1, 263, Outputs::CRT::ColourSpace::YIQ, 228, 1, 1));
|
crt_.reset(new Outputs::CRT::CRT(228, 1, 263, Outputs::CRT::ColourSpace::YIQ, 228, 1, false, 1));
|
||||||
crt_->set_output_device(Outputs::CRT::Television);
|
crt_->set_output_device(Outputs::CRT::Television);
|
||||||
|
|
||||||
// this is the NTSC phase offset function; see below for PAL
|
// this is the NTSC phase offset function; see below for PAL
|
||||||
@ -93,7 +93,7 @@ void Machine::switch_region()
|
|||||||
"return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);"
|
"return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);"
|
||||||
"}");
|
"}");
|
||||||
|
|
||||||
crt_->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1);
|
crt_->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1, true);
|
||||||
|
|
||||||
is_pal_region_ = true;
|
is_pal_region_ = true;
|
||||||
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
|
speaker_->set_input_rate((float)(get_clock_rate() / 38.0));
|
||||||
|
@ -43,8 +43,7 @@ Machine::Machine() :
|
|||||||
display_output_position_(0),
|
display_output_position_(0),
|
||||||
audio_output_position_(0),
|
audio_output_position_(0),
|
||||||
current_pixel_line_(-1),
|
current_pixel_line_(-1),
|
||||||
use_fast_tape_hack_(false),
|
use_fast_tape_hack_(false)
|
||||||
phase_(0)
|
|
||||||
{
|
{
|
||||||
memset(key_states_, 0, sizeof(key_states_));
|
memset(key_states_, 0, sizeof(key_states_));
|
||||||
memset(palette_, 0xf, sizeof(palette_));
|
memset(palette_, 0xf, sizeof(palette_));
|
||||||
@ -452,8 +451,6 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
|||||||
|
|
||||||
frame_cycles_ += cycles;
|
frame_cycles_ += cycles;
|
||||||
|
|
||||||
if(!(frame_cycles_&127)) phase_ += 64;
|
|
||||||
|
|
||||||
// deal with frame wraparound by updating the two dependent subsystems
|
// deal with frame wraparound by updating the two dependent subsystems
|
||||||
// as though the exact end of frame had been hit, then reset those
|
// as though the exact end of frame had been hit, then reset those
|
||||||
// and allow the frame cycle counter to assume its real value
|
// and allow the frame cycle counter to assume its real value
|
||||||
@ -874,7 +871,7 @@ inline void Machine::update_display()
|
|||||||
if(this_cycle < 24)
|
if(this_cycle < 24)
|
||||||
{
|
{
|
||||||
if(final_cycle < 24) return;
|
if(final_cycle < 24) return;
|
||||||
crt_->output_colour_burst((24-9) * crt_cycles_multiplier, phase_, 12);
|
crt_->output_default_colour_burst((24-9) * crt_cycles_multiplier);
|
||||||
display_output_position_ += 24-9;
|
display_output_position_ += 24-9;
|
||||||
this_cycle = 24;
|
this_cycle = 24;
|
||||||
// TODO: phase shouldn't be zero on every line
|
// TODO: phase shouldn't be zero on every line
|
||||||
|
@ -135,7 +135,6 @@ class Machine:
|
|||||||
// Counters related to simultaneous subsystems
|
// Counters related to simultaneous subsystems
|
||||||
unsigned int frame_cycles_, display_output_position_;
|
unsigned int frame_cycles_, display_output_position_;
|
||||||
unsigned int audio_output_position_, audio_output_position_error_;
|
unsigned int audio_output_position_, audio_output_position_error_;
|
||||||
uint8_t phase_;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint16_t forty1bpp[256];
|
uint16_t forty1bpp[256];
|
||||||
|
@ -82,6 +82,10 @@ void Machine::set_rom(ROM rom, const std::vector<uint8_t> &data)
|
|||||||
case BASIC11: basic11_rom_ = std::move(data); break;
|
case BASIC11: basic11_rom_ = std::move(data); break;
|
||||||
case BASIC10: basic10_rom_ = std::move(data); break;
|
case BASIC10: basic10_rom_ = std::move(data); break;
|
||||||
case Microdisc: microdisc_rom_ = std::move(data); break;
|
case Microdisc: microdisc_rom_ = std::move(data); break;
|
||||||
|
case Colour:
|
||||||
|
colour_rom_ = std::move(data);
|
||||||
|
if(video_output_) video_output_->set_colour_rom(colour_rom_);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +176,10 @@ void Machine::update_video()
|
|||||||
|
|
||||||
void Machine::setup_output(float aspect_ratio)
|
void Machine::setup_output(float aspect_ratio)
|
||||||
{
|
{
|
||||||
video_output_.reset(new VideoOutput(ram_));
|
|
||||||
via_.ay8910.reset(new GI::AY38910());
|
via_.ay8910.reset(new GI::AY38910());
|
||||||
via_.ay8910->set_clock_rate(1000000);
|
via_.ay8910->set_clock_rate(1000000);
|
||||||
|
video_output_.reset(new VideoOutput(ram_));
|
||||||
|
if(!colour_rom_.empty()) video_output_->set_colour_rom(colour_rom_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::close_output()
|
void Machine::close_output()
|
||||||
@ -213,6 +218,11 @@ void Machine::set_use_fast_tape_hack(bool activate)
|
|||||||
use_fast_tape_hack_ = activate;
|
use_fast_tape_hack_ = activate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Machine::set_output_device(Outputs::CRT::OutputDevice output_device)
|
||||||
|
{
|
||||||
|
video_output_->set_output_device(output_device);
|
||||||
|
}
|
||||||
|
|
||||||
void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player)
|
void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player)
|
||||||
{
|
{
|
||||||
// set CB1
|
// set CB1
|
||||||
|
@ -53,7 +53,7 @@ enum Key: uint16_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum ROM {
|
enum ROM {
|
||||||
BASIC10, BASIC11, Microdisc
|
BASIC10, BASIC11, Microdisc, Colour
|
||||||
};
|
};
|
||||||
|
|
||||||
class Machine:
|
class Machine:
|
||||||
@ -73,6 +73,7 @@ class Machine:
|
|||||||
void clear_all_keys();
|
void clear_all_keys();
|
||||||
|
|
||||||
void set_use_fast_tape_hack(bool activate);
|
void set_use_fast_tape_hack(bool activate);
|
||||||
|
void set_output_device(Outputs::CRT::OutputDevice output_device);
|
||||||
|
|
||||||
// to satisfy ConfigurationTarget::Machine
|
// to satisfy ConfigurationTarget::Machine
|
||||||
void configure_as_target(const StaticAnalyser::Target &target);
|
void configure_as_target(const StaticAnalyser::Target &target);
|
||||||
@ -103,7 +104,7 @@ class Machine:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// RAM and ROM
|
// RAM and ROM
|
||||||
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_;
|
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_;
|
||||||
uint8_t ram_[65536], rom_[16384];
|
uint8_t ram_[65536], rom_[16384];
|
||||||
int cycles_since_video_update_;
|
int cycles_since_video_update_;
|
||||||
inline void update_video();
|
inline void update_video();
|
||||||
|
@ -24,24 +24,57 @@ VideoOutput::VideoOutput(uint8_t *memory) :
|
|||||||
frame_counter_(0), counter_(0),
|
frame_counter_(0), counter_(0),
|
||||||
is_graphics_mode_(false),
|
is_graphics_mode_(false),
|
||||||
character_set_base_address_(0xb400),
|
character_set_base_address_(0xb400),
|
||||||
phase_(0),
|
|
||||||
v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition),
|
v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition),
|
||||||
counter_period_(PAL50Period), next_frame_is_sixty_hertz_(false),
|
counter_period_(PAL50Period), next_frame_is_sixty_hertz_(false),
|
||||||
crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::CRT::DisplayType::PAL50, 1))
|
crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::CRT::DisplayType::PAL50, 2))
|
||||||
{
|
{
|
||||||
// TODO: this is a copy and paste from the Electron; factor out.
|
|
||||||
crt_->set_rgb_sampling_function(
|
crt_->set_rgb_sampling_function(
|
||||||
"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)"
|
"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)"
|
||||||
"{"
|
"{"
|
||||||
"uint texValue = texture(sampler, coordinate).r;"
|
"uint texValue = texture(sampler, coordinate).r;"
|
||||||
"texValue >>= 4 - (int(icoordinate.x * 8) & 4);"
|
|
||||||
"return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));"
|
"return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));"
|
||||||
"}");
|
"}");
|
||||||
|
crt_->set_composite_sampling_function(
|
||||||
|
"float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)"
|
||||||
|
"{"
|
||||||
|
"uint texValue = uint(dot(texture(sampler, coordinate).rg, uvec2(1, 256)));"
|
||||||
|
"uint iPhase = uint((phase + 3.141592654 + 0.39269908175) * 2.0 / 3.141592654) & 3u;"
|
||||||
|
"texValue = (texValue >> (4u*(3u - iPhase))) & 15u;"
|
||||||
|
"return (float(texValue) - 4.0) / 20.0;"
|
||||||
|
"}"
|
||||||
|
);
|
||||||
|
|
||||||
crt_->set_output_device(Outputs::CRT::Television);
|
set_output_device(Outputs::CRT::Television);
|
||||||
crt_->set_visible_area(crt_->get_rect_for_area(50, 224, 16 * 6, 40 * 6, 4.0f / 3.0f));
|
crt_->set_visible_area(crt_->get_rect_for_area(50, 224, 16 * 6, 40 * 6, 4.0f / 3.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoOutput::set_output_device(Outputs::CRT::OutputDevice output_device)
|
||||||
|
{
|
||||||
|
output_device_ = output_device;
|
||||||
|
crt_->set_output_device(output_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoOutput::set_colour_rom(const std::vector<uint8_t> &rom)
|
||||||
|
{
|
||||||
|
for(size_t c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
size_t index = (c << 2);
|
||||||
|
uint16_t rom_value = (uint16_t)(((uint16_t)rom[index] << 8) | (uint16_t)rom[index+1]);
|
||||||
|
rom_value = (rom_value & 0xff00) | ((rom_value >> 4)&0x000f) | ((rom_value << 4)&0x00f0);
|
||||||
|
colour_forms_[c] = rom_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for big endianness and byte swap if required
|
||||||
|
uint16_t test_value = 0x0001;
|
||||||
|
if(*(uint8_t *)&test_value != 0x01)
|
||||||
|
{
|
||||||
|
for(size_t c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
colour_forms_[c] = (uint16_t)((colour_forms_[c] >> 8) | (colour_forms_[c] << 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Outputs::CRT::CRT> VideoOutput::get_crt()
|
std::shared_ptr<Outputs::CRT::CRT> VideoOutput::get_crt()
|
||||||
{
|
{
|
||||||
return crt_;
|
return crt_;
|
||||||
@ -71,16 +104,14 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
|||||||
// this is a pixel line
|
// this is a pixel line
|
||||||
if(!h_counter)
|
if(!h_counter)
|
||||||
{
|
{
|
||||||
ink_ = 0xff;
|
ink_ = 0x7;
|
||||||
paper_ = 0x00;
|
paper_ = 0x0;
|
||||||
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;
|
pixel_target_ = (uint16_t *)crt_->allocate_write_area(240);
|
||||||
pixel_target_ = crt_->allocate_write_area(120);
|
|
||||||
|
|
||||||
if(!counter_)
|
if(!counter_)
|
||||||
{
|
{
|
||||||
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;
|
||||||
@ -111,35 +142,44 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
|||||||
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) ? 0x7 : 0x0;
|
||||||
pixels &= blink_mask;
|
pixels &= blink_mask;
|
||||||
|
|
||||||
if(control_byte & 0x60)
|
if(control_byte & 0x60)
|
||||||
{
|
{
|
||||||
if(pixel_target_)
|
if(pixel_target_)
|
||||||
{
|
{
|
||||||
uint8_t colours[2] = {
|
uint16_t colours[2];
|
||||||
(uint8_t)(paper_ ^ inverse_mask),
|
if(output_device_ == Outputs::CRT::Monitor)
|
||||||
(uint8_t)(ink_ ^ inverse_mask),
|
{
|
||||||
};
|
colours[0] = (uint8_t)(paper_ ^ inverse_mask);
|
||||||
|
colours[1] = (uint8_t)(ink_ ^ inverse_mask);
|
||||||
pixel_target_[0] = (colours[(pixels >> 4)&1] & 0x0f) | (colours[(pixels >> 5)&1] & 0xf0);
|
}
|
||||||
pixel_target_[1] = (colours[(pixels >> 2)&1] & 0x0f) | (colours[(pixels >> 3)&1] & 0xf0);
|
else
|
||||||
pixel_target_[2] = (colours[(pixels >> 0)&1] & 0x0f) | (colours[(pixels >> 1)&1] & 0xf0);
|
{
|
||||||
|
colours[0] = colour_forms_[paper_ ^ inverse_mask];
|
||||||
|
colours[1] = colour_forms_[ink_ ^ inverse_mask];
|
||||||
|
}
|
||||||
|
pixel_target_[0] = colours[(pixels >> 5)&1];
|
||||||
|
pixel_target_[1] = colours[(pixels >> 4)&1];
|
||||||
|
pixel_target_[2] = colours[(pixels >> 3)&1];
|
||||||
|
pixel_target_[3] = colours[(pixels >> 2)&1];
|
||||||
|
pixel_target_[4] = colours[(pixels >> 1)&1];
|
||||||
|
pixel_target_[5] = colours[(pixels >> 0)&1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch(control_byte & 0x1f)
|
switch(control_byte & 0x1f)
|
||||||
{
|
{
|
||||||
case 0x00: ink_ = 0x00; break;
|
case 0x00: ink_ = 0x0; break;
|
||||||
case 0x01: ink_ = 0x44; break;
|
case 0x01: ink_ = 0x4; break;
|
||||||
case 0x02: ink_ = 0x22; break;
|
case 0x02: ink_ = 0x2; break;
|
||||||
case 0x03: ink_ = 0x66; break;
|
case 0x03: ink_ = 0x6; break;
|
||||||
case 0x04: ink_ = 0x11; break;
|
case 0x04: ink_ = 0x1; break;
|
||||||
case 0x05: ink_ = 0x55; break;
|
case 0x05: ink_ = 0x5; break;
|
||||||
case 0x06: ink_ = 0x33; break;
|
case 0x06: ink_ = 0x3; break;
|
||||||
case 0x07: ink_ = 0x77; break;
|
case 0x07: ink_ = 0x7; break;
|
||||||
|
|
||||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||||
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
||||||
@ -149,14 +189,14 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
|||||||
set_character_set_base_address();
|
set_character_set_base_address();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x10: paper_ = 0x00; break;
|
case 0x10: paper_ = 0x0; break;
|
||||||
case 0x11: paper_ = 0x44; break;
|
case 0x11: paper_ = 0x4; break;
|
||||||
case 0x12: paper_ = 0x22; break;
|
case 0x12: paper_ = 0x2; break;
|
||||||
case 0x13: paper_ = 0x66; break;
|
case 0x13: paper_ = 0x6; break;
|
||||||
case 0x14: paper_ = 0x11; break;
|
case 0x14: paper_ = 0x1; break;
|
||||||
case 0x15: paper_ = 0x55; break;
|
case 0x15: paper_ = 0x5; break;
|
||||||
case 0x16: paper_ = 0x33; break;
|
case 0x16: paper_ = 0x3; break;
|
||||||
case 0x17: paper_ = 0x77; break;
|
case 0x17: paper_ = 0x7; break;
|
||||||
|
|
||||||
case 0x18: case 0x19: case 0x1a: case 0x1b:
|
case 0x18: case 0x19: case 0x1a: case 0x1b:
|
||||||
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
||||||
@ -166,15 +206,21 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
|||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
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] = pixel_target_[3] =
|
||||||
|
pixel_target_[4] = pixel_target_[5] =
|
||||||
|
(output_device_ == Outputs::CRT::Monitor) ? paper_ ^ inverse_mask : colour_forms_[paper_ ^ inverse_mask];
|
||||||
}
|
}
|
||||||
if(pixel_target_) pixel_target_ += 3;
|
}
|
||||||
|
if(pixel_target_) pixel_target_ += 6;
|
||||||
h_counter++;
|
h_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(h_counter == 40)
|
if(h_counter == 40)
|
||||||
{
|
{
|
||||||
crt_->output_data(40 * 6, 2);
|
crt_->output_data(40 * 6, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -196,7 +242,7 @@ void VideoOutput::run_for_cycles(int number_of_cycles)
|
|||||||
else if(h_counter < 56)
|
else if(h_counter < 56)
|
||||||
{
|
{
|
||||||
cycles_run_for = 56 - h_counter;
|
cycles_run_for = 56 - h_counter;
|
||||||
clamp(crt_->output_colour_burst(2 * 6, phase_, 128));
|
clamp(crt_->output_default_colour_burst(2 * 6));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,8 @@ class VideoOutput {
|
|||||||
VideoOutput(uint8_t *memory);
|
VideoOutput(uint8_t *memory);
|
||||||
std::shared_ptr<Outputs::CRT::CRT> get_crt();
|
std::shared_ptr<Outputs::CRT::CRT> get_crt();
|
||||||
void run_for_cycles(int number_of_cycles);
|
void run_for_cycles(int number_of_cycles);
|
||||||
|
void set_colour_rom(const std::vector<uint8_t> &rom);
|
||||||
|
void set_output_device(Outputs::CRT::OutputDevice output_device);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t *ram_;
|
uint8_t *ram_;
|
||||||
@ -27,8 +29,10 @@ 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 target
|
// Output target and device
|
||||||
uint8_t *pixel_target_;
|
uint16_t *pixel_target_;
|
||||||
|
uint16_t colour_forms_[8];
|
||||||
|
Outputs::CRT::OutputDevice output_device_;
|
||||||
|
|
||||||
// Registers
|
// Registers
|
||||||
uint8_t ink_, paper_;
|
uint8_t ink_, paper_;
|
||||||
@ -41,8 +45,6 @@ class VideoOutput {
|
|||||||
bool use_alternative_character_set_;
|
bool use_alternative_character_set_;
|
||||||
bool use_double_height_characters_;
|
bool use_double_height_characters_;
|
||||||
bool blink_text_;
|
bool blink_text_;
|
||||||
|
|
||||||
uint8_t phase_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,12 @@
|
|||||||
{
|
{
|
||||||
NSData *basic10 = [self rom:@"basic10"];
|
NSData *basic10 = [self rom:@"basic10"];
|
||||||
NSData *basic11 = [self rom:@"basic11"];
|
NSData *basic11 = [self rom:@"basic11"];
|
||||||
|
NSData *colour = [self rom:@"colour"];
|
||||||
NSData *microdisc = [self rom:@"microdisc"];
|
NSData *microdisc = [self rom:@"microdisc"];
|
||||||
|
|
||||||
if(basic10) _oric.set_rom(Oric::BASIC10, basic10.stdVector8);
|
if(basic10) _oric.set_rom(Oric::BASIC10, basic10.stdVector8);
|
||||||
if(basic11) _oric.set_rom(Oric::BASIC11, basic11.stdVector8);
|
if(basic11) _oric.set_rom(Oric::BASIC11, basic11.stdVector8);
|
||||||
|
if(colour) _oric.set_rom(Oric::Colour, colour.stdVector8);
|
||||||
if(microdisc) _oric.set_rom(Oric::Microdisc, microdisc.stdVector8);
|
if(microdisc) _oric.set_rom(Oric::Microdisc, microdisc.stdVector8);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@ -150,7 +152,7 @@
|
|||||||
- (void)setUseCompositeOutput:(BOOL)useCompositeOutput {
|
- (void)setUseCompositeOutput:(BOOL)useCompositeOutput {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
_useCompositeOutput = useCompositeOutput;
|
_useCompositeOutput = useCompositeOutput;
|
||||||
_oric.get_crt()->set_output_device(useCompositeOutput ? Outputs::CRT::Television : Outputs::CRT::Monitor);
|
_oric.set_output_device(useCompositeOutput ? Outputs::CRT::Television : Outputs::CRT::Monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
using namespace Outputs::CRT;
|
using namespace Outputs::CRT;
|
||||||
|
|
||||||
void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator)
|
void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, bool should_alternate)
|
||||||
{
|
{
|
||||||
openGL_output_builder_.set_colour_format(colour_space, colour_cycle_numerator, colour_cycle_denominator);
|
openGL_output_builder_.set_colour_format(colour_space, colour_cycle_numerator, colour_cycle_denominator);
|
||||||
|
|
||||||
@ -29,6 +29,11 @@ void CRT::set_new_timing(unsigned int cycles_per_line, unsigned int height_of_di
|
|||||||
// for horizontal retrace and 500 to 750 µs for vertical retrace in NTSC and PAL TV."
|
// for horizontal retrace and 500 to 750 µs for vertical retrace in NTSC and PAL TV."
|
||||||
|
|
||||||
time_multiplier_ = IntermediateBufferWidth / cycles_per_line;
|
time_multiplier_ = IntermediateBufferWidth / cycles_per_line;
|
||||||
|
phase_denominator_ = cycles_per_line * colour_cycle_denominator;
|
||||||
|
phase_numerator_ = 0;
|
||||||
|
colour_cycle_numerator_ = colour_cycle_numerator * time_multiplier_;
|
||||||
|
phase_alternates_ = should_alternate;
|
||||||
|
is_alernate_line_ &= phase_alternates_;
|
||||||
unsigned int multiplied_cycles_per_line = cycles_per_line * time_multiplier_;
|
unsigned int multiplied_cycles_per_line = cycles_per_line * time_multiplier_;
|
||||||
|
|
||||||
// generate timing values implied by the given arbuments
|
// generate timing values implied by the given arbuments
|
||||||
@ -50,11 +55,11 @@ void CRT::set_new_display_type(unsigned int cycles_per_line, DisplayType display
|
|||||||
switch(displayType)
|
switch(displayType)
|
||||||
{
|
{
|
||||||
case DisplayType::PAL50:
|
case DisplayType::PAL50:
|
||||||
set_new_timing(cycles_per_line, 312, ColourSpace::YUV, 709379, 2500); // i.e. 283.7516
|
set_new_timing(cycles_per_line, 312, ColourSpace::YUV, 709379, 2500, true); // i.e. 283.7516
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DisplayType::NTSC60:
|
case DisplayType::NTSC60:
|
||||||
set_new_timing(cycles_per_line, 262, ColourSpace::YIQ, 545, 2);
|
set_new_timing(cycles_per_line, 262, ColourSpace::YIQ, 545, 2, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,12 +72,13 @@ CRT::CRT(unsigned int common_output_divisor, unsigned int buffer_depth) :
|
|||||||
is_writing_composite_run_(false),
|
is_writing_composite_run_(false),
|
||||||
delegate_(nullptr),
|
delegate_(nullptr),
|
||||||
frames_since_last_delegate_call_(0),
|
frames_since_last_delegate_call_(0),
|
||||||
openGL_output_builder_(buffer_depth) {}
|
openGL_output_builder_(buffer_depth),
|
||||||
|
is_alernate_line_(false) {}
|
||||||
|
|
||||||
CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int buffer_depth) :
|
CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, bool should_alternate, unsigned int buffer_depth) :
|
||||||
CRT(common_output_divisor, buffer_depth)
|
CRT(common_output_divisor, buffer_depth)
|
||||||
{
|
{
|
||||||
set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator);
|
set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator, should_alternate);
|
||||||
}
|
}
|
||||||
|
|
||||||
CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, DisplayType displayType, unsigned int buffer_depth) :
|
CRT::CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, DisplayType displayType, unsigned int buffer_depth) :
|
||||||
@ -124,6 +130,8 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
|||||||
// get the next sync event and its timing; hsync request is instantaneous (being edge triggered) so
|
// get the next sync event and its timing; hsync request is instantaneous (being edge triggered) so
|
||||||
// set it to false for the next run through this loop (if any)
|
// set it to false for the next run through this loop (if any)
|
||||||
unsigned int next_run_length = std::min(time_until_vertical_sync_event, time_until_horizontal_sync_event);
|
unsigned int next_run_length = std::min(time_until_vertical_sync_event, time_until_horizontal_sync_event);
|
||||||
|
phase_numerator_ += next_run_length * colour_cycle_numerator_;
|
||||||
|
phase_numerator_ %= phase_denominator_;
|
||||||
|
|
||||||
hsync_requested = false;
|
hsync_requested = false;
|
||||||
vsync_requested = false;
|
vsync_requested = false;
|
||||||
@ -171,6 +179,8 @@ void CRT::advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bo
|
|||||||
(honoured_event == Flywheel::SyncEvent::StartRetrace && is_writing_composite_run_) ||
|
(honoured_event == Flywheel::SyncEvent::StartRetrace && is_writing_composite_run_) ||
|
||||||
(honoured_event == Flywheel::SyncEvent::EndRetrace && !horizontal_flywheel_->is_in_retrace() && !vertical_flywheel_->is_in_retrace());
|
(honoured_event == Flywheel::SyncEvent::EndRetrace && !horizontal_flywheel_->is_in_retrace() && !vertical_flywheel_->is_in_retrace());
|
||||||
|
|
||||||
|
if(next_run_length == time_until_horizontal_sync_event && next_horizontal_sync_event == Flywheel::SyncEvent::StartRetrace) is_alernate_line_ ^= phase_alternates_;
|
||||||
|
|
||||||
if(needs_endpoint)
|
if(needs_endpoint)
|
||||||
{
|
{
|
||||||
if(
|
if(
|
||||||
@ -329,6 +339,17 @@ void CRT::output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint
|
|||||||
output_scan(&scan);
|
output_scan(&scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CRT::output_default_colour_burst(unsigned int number_of_cycles)
|
||||||
|
{
|
||||||
|
Scan scan {
|
||||||
|
.type = Scan::Type::ColourBurst,
|
||||||
|
.number_of_cycles = number_of_cycles,
|
||||||
|
.phase = (uint8_t)((phase_numerator_ * 255) / phase_denominator_ + (is_alernate_line_ ? 128 : 0)),
|
||||||
|
.amplitude = 32
|
||||||
|
};
|
||||||
|
output_scan(&scan);
|
||||||
|
}
|
||||||
|
|
||||||
void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider)
|
void CRT::output_data(unsigned int number_of_cycles, unsigned int source_divider)
|
||||||
{
|
{
|
||||||
openGL_output_builder_.texture_builder.reduce_previous_allocation_to(number_of_cycles / source_divider);
|
openGL_output_builder_.texture_builder.reduce_previous_allocation_to(number_of_cycles / source_divider);
|
||||||
|
@ -46,7 +46,6 @@ class CRT {
|
|||||||
int sync_capacitor_charge_threshold_; // this charges up during times of sync and depletes otherwise; needs to hit a required threshold to trigger a vertical sync
|
int sync_capacitor_charge_threshold_; // this charges up during times of sync and depletes otherwise; needs to hit a required threshold to trigger a vertical sync
|
||||||
unsigned int sync_period_;
|
unsigned int sync_period_;
|
||||||
|
|
||||||
// each call to output_* generates a scan. A two-slot queue for scans allows edge extensions.
|
|
||||||
struct Scan {
|
struct Scan {
|
||||||
enum Type {
|
enum Type {
|
||||||
Sync, Level, Data, Blank, ColourBurst
|
Sync, Level, Data, Blank, ColourBurst
|
||||||
@ -64,6 +63,9 @@ class CRT {
|
|||||||
uint16_t colour_burst_time_;
|
uint16_t colour_burst_time_;
|
||||||
bool is_writing_composite_run_;
|
bool is_writing_composite_run_;
|
||||||
|
|
||||||
|
unsigned int phase_denominator_, phase_numerator_, colour_cycle_numerator_;
|
||||||
|
bool is_alernate_line_, phase_alternates_;
|
||||||
|
|
||||||
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data
|
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data
|
||||||
void advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Scan::Type type);
|
void advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const bool vsync_charging, const Scan::Type type);
|
||||||
|
|
||||||
@ -113,7 +115,7 @@ class CRT {
|
|||||||
|
|
||||||
@see @c set_rgb_sampling_function , @c set_composite_sampling_function
|
@see @c set_rgb_sampling_function , @c set_composite_sampling_function
|
||||||
*/
|
*/
|
||||||
CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, unsigned int buffer_depth);
|
CRT(unsigned int cycles_per_line, unsigned int common_output_divisor, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, bool should_alternate, unsigned int buffer_depth);
|
||||||
|
|
||||||
/*! Constructs the CRT with the specified clock rate, with the display height and colour
|
/*! Constructs the CRT with the specified clock rate, with the display height and colour
|
||||||
subcarrier frequency dictated by a standard display type and with the requested number of
|
subcarrier frequency dictated by a standard display type and with the requested number of
|
||||||
@ -126,7 +128,7 @@ class CRT {
|
|||||||
|
|
||||||
/*! Resets the CRT with new timing information. The CRT then continues as though the new timing had
|
/*! Resets the CRT with new timing information. The CRT then continues as though the new timing had
|
||||||
been provided at construction. */
|
been provided at construction. */
|
||||||
void set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator);
|
void set_new_timing(unsigned int cycles_per_line, unsigned int height_of_display, ColourSpace colour_space, unsigned int colour_cycle_numerator, unsigned int colour_cycle_denominator, bool should_alternate);
|
||||||
|
|
||||||
/*! Resets the CRT with new timing information derived from a new display type. The CRT then continues
|
/*! Resets the CRT with new timing information derived from a new display type. The CRT then continues
|
||||||
as though the new timing had been provided at construction. */
|
as though the new timing had been provided at construction. */
|
||||||
@ -175,6 +177,12 @@ class CRT {
|
|||||||
*/
|
*/
|
||||||
void output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t amplitude);
|
void output_colour_burst(unsigned int number_of_cycles, uint8_t phase, uint8_t amplitude);
|
||||||
|
|
||||||
|
/*! Outputs a colour burst exactly in phase with CRT expectations using the idiomatic amplitude.
|
||||||
|
|
||||||
|
@param number_of_cycles The length of the colour burst;
|
||||||
|
*/
|
||||||
|
void output_default_colour_burst(unsigned int number_of_cycles);
|
||||||
|
|
||||||
/*! Attempts to allocate the given number of output samples for writing.
|
/*! Attempts to allocate the given number of output samples for writing.
|
||||||
|
|
||||||
The beginning of the most recently allocated area is used as the start
|
The beginning of the most recently allocated area is used as the start
|
||||||
|
@ -78,7 +78,7 @@ ArrayBuilder::Submission ArrayBuilder::submit()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArrayBuilder::Buffer::Buffer(size_t size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function) :
|
ArrayBuilder::Buffer::Buffer(size_t size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function) :
|
||||||
is_full(false), was_reset(false),
|
is_full(false),
|
||||||
submission_function_(submission_function),
|
submission_function_(submission_function),
|
||||||
allocated_data(0), flushed_data(0), submitted_data(0)
|
allocated_data(0), flushed_data(0), submitted_data(0)
|
||||||
{
|
{
|
||||||
@ -137,14 +137,6 @@ void ArrayBuilder::Buffer::flush()
|
|||||||
}
|
}
|
||||||
|
|
||||||
flushed_data = allocated_data;
|
flushed_data = allocated_data;
|
||||||
|
|
||||||
if(was_reset)
|
|
||||||
{
|
|
||||||
allocated_data = 0;
|
|
||||||
flushed_data = 0;
|
|
||||||
submitted_data = 0;
|
|
||||||
was_reset = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ArrayBuilder::Buffer::submit(bool is_input)
|
size_t ArrayBuilder::Buffer::submit(bool is_input)
|
||||||
@ -171,6 +163,8 @@ void ArrayBuilder::Buffer::bind()
|
|||||||
|
|
||||||
void ArrayBuilder::Buffer::reset()
|
void ArrayBuilder::Buffer::reset()
|
||||||
{
|
{
|
||||||
was_reset = true;
|
|
||||||
is_full = false;
|
is_full = false;
|
||||||
|
allocated_data = 0;
|
||||||
|
flushed_data = 0;
|
||||||
|
submitted_data = 0;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ class ArrayBuilder {
|
|||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_full, was_reset;
|
bool is_full;
|
||||||
GLuint buffer;
|
GLuint buffer;
|
||||||
std::function<void(bool is_input, uint8_t *, size_t)> submission_function_;
|
std::function<void(bool is_input, uint8_t *, size_t)> submission_function_;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
@ -36,7 +36,7 @@ const GLsizei InputBufferBuilderWidth = 2048;
|
|||||||
const GLsizei InputBufferBuilderHeight = 512;
|
const GLsizei InputBufferBuilderHeight = 512;
|
||||||
|
|
||||||
// This is the size of the intermediate buffers used during composite to RGB conversion
|
// This is the size of the intermediate buffers used during composite to RGB conversion
|
||||||
const GLsizei IntermediateBufferWidth = 2048;
|
const GLsizei IntermediateBufferWidth = 4096;
|
||||||
const GLsizei IntermediateBufferHeight = 512;
|
const GLsizei IntermediateBufferHeight = 512;
|
||||||
|
|
||||||
// Some internal buffer sizes
|
// Some internal buffer sizes
|
||||||
|
@ -385,7 +385,7 @@ void OpenGLOutputBuilder::set_timing_uniforms()
|
|||||||
|
|
||||||
float colour_subcarrier_frequency = (float)colour_cycle_numerator_ / (float)colour_cycle_denominator_;
|
float colour_subcarrier_frequency = (float)colour_cycle_numerator_ / (float)colour_cycle_denominator_;
|
||||||
if(composite_separation_filter_program_) composite_separation_filter_program_->set_separation_frequency(cycles_per_line_, colour_subcarrier_frequency);
|
if(composite_separation_filter_program_) composite_separation_filter_program_->set_separation_frequency(cycles_per_line_, colour_subcarrier_frequency);
|
||||||
if(composite_y_filter_shader_program_) composite_y_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.66f);
|
if(composite_y_filter_shader_program_) composite_y_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.25f);
|
||||||
if(composite_chrominance_filter_shader_program_) composite_chrominance_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.5f);
|
if(composite_chrominance_filter_shader_program_) composite_chrominance_filter_shader_program_->set_filter_coefficients(cycles_per_line_, colour_subcarrier_frequency * 0.5f);
|
||||||
if(rgb_filter_shader_program_) rgb_filter_shader_program_->set_filter_coefficients(cycles_per_line_, (float)input_frequency_ * 0.5f);
|
if(rgb_filter_shader_program_) rgb_filter_shader_program_->set_filter_coefficients(cycles_per_line_, (float)input_frequency_ * 0.5f);
|
||||||
}
|
}
|
||||||
|
8
ROMImages/Oric/readme.txt
Normal file
8
ROMImages/Oric/readme.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
ROM files would ordinarily go here; the copyright status of these is uncertain so they have not been included in this repository.
|
||||||
|
|
||||||
|
Expected files:
|
||||||
|
|
||||||
|
basic10.rom
|
||||||
|
basic11.rom
|
||||||
|
colour.rom
|
||||||
|
microdisc.rom
|
Loading…
Reference in New Issue
Block a user