1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-07 16:37:24 +00:00

Re-establishes output from the machines with 9918s and derivatives.

This commit is contained in:
Thomas Harte 2018-11-14 22:25:19 -05:00
parent a47de9a884
commit 9dff13cbbf
6 changed files with 81 additions and 96 deletions

View File

@ -49,9 +49,8 @@ struct ReverseTable {
}
Base::Base(Personality p) :
personality_(p)//,
// crt_(new Outputs::CRT::CRT(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, 4))
{
personality_(p),
crt_(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, Outputs::Display::InputDataType::Red8Green8Blue8) {
switch(p) {
case TI::TMS::TMS9918A:
@ -87,19 +86,19 @@ TMS9918::TMS9918(Personality p):
Base(p) {
// Unimaginatively, this class just passes RGB through to the shader. Investigation is needed
// into whether there's a more natural form.
// crt_->set_rgb_sampling_function(
// crt_.set_rgb_sampling_function(
// "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)"
// "{"
// "return texture(sampler, coordinate).rgb / vec3(255.0);"
// "}");
// crt_->set_video_signal(Outputs::Display::VideoSignal::RGB);
crt_->set_visible_area(Outputs::Display::Rect(0.055f, 0.025f, 0.9f, 0.9f));
crt_.set_visible_area(Outputs::Display::Rect(0.055f, 0.025f, 0.9f, 0.9f));
// The TMS remains in-phase with the NTSC colour clock; this is an empirical measurement
// intended to produce the correct relationship between the hard edges between pixels and
// the colour clock. It was eyeballed rather than derived from any knowledge of the TMS
// colour burst generator because I've yet to find any.
crt_->set_immediate_default_phase(0.85f);
crt_.set_immediate_default_phase(0.85f);
}
void TMS9918::set_tv_standard(TVStandard standard) {
@ -108,18 +107,18 @@ void TMS9918::set_tv_standard(TVStandard standard) {
case TVStandard::PAL:
mode_timing_.total_lines = 313;
mode_timing_.first_vsync_line = 253;
crt_->set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::PAL50);
crt_.set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::PAL50);
break;
default:
mode_timing_.total_lines = 262;
mode_timing_.first_vsync_line = 227;
crt_->set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::NTSC60);
crt_.set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::NTSC60);
break;
}
}
Outputs::CRT::CRT *TMS9918::get_crt() {
return crt_.get();
void TMS9918::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
void Base::LineBuffer::reset_sprite_collection() {
@ -368,7 +367,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
if(read_pointer_.row >= mode_timing_.first_vsync_line && read_pointer_.row < mode_timing_.first_vsync_line+4) {
// Vertical sync.
if(end_column == 342) {
crt_->output_sync(342 * 4);
crt_.output_sync(342 * 4);
}
} else {
// Right border.
@ -378,11 +377,11 @@ void TMS9918::run_for(const HalfCycles cycles) {
// and 58+15 = 73. So output the lot when the
// cursor passes 73.
if(read_pointer_.column < 73 && end_column >= 73) {
crt_->output_blank(8*4);
crt_->output_sync(26*4);
crt_->output_blank(2*4);
crt_->output_default_colour_burst(14*4);
crt_->output_blank(8*4);
crt_.output_blank(8*4);
crt_.output_sync(26*4);
crt_.output_blank(2*4);
crt_.output_default_colour_burst(14*4);
crt_.output_blank(8*4);
}
// Border colour for the rest of the line.
@ -394,11 +393,11 @@ void TMS9918::run_for(const HalfCycles cycles) {
// Blanking region.
if(read_pointer_.column < 73 && end_column >= 73) {
crt_->output_blank(8*4);
crt_->output_sync(26*4);
crt_->output_blank(2*4);
crt_->output_default_colour_burst(14*4);
crt_->output_blank(8*4);
crt_.output_blank(8*4);
crt_.output_sync(26*4);
crt_.output_blank(2*4);
crt_.output_default_colour_burst(14*4);
crt_.output_blank(8*4);
}
// Left border.
@ -411,7 +410,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
if(!asked_for_write_area_) {
asked_for_write_area_ = true;
pixel_origin_ = pixel_target_ = reinterpret_cast<uint32_t *>(
crt_->begin_data(size_t(line_buffer.next_border_column - line_buffer.first_pixel_output_column))
crt_.begin_data(size_t(line_buffer.next_border_column - line_buffer.first_pixel_output_column))
);
}
@ -429,7 +428,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
if(end == line_buffer.next_border_column) {
const int length = line_buffer.next_border_column - line_buffer.first_pixel_output_column;
crt_->output_data(length * 4, size_t(length));
crt_.output_data(length * 4, size_t(length));
pixel_origin_ = pixel_target_ = nullptr;
asked_for_write_area_ = false;
}
@ -471,16 +470,16 @@ void Base::output_border(int cycles, uint32_t cram_dot) {
palette[background_colour_];
if(cram_dot) {
uint32_t *const pixel_target = reinterpret_cast<uint32_t *>(crt_->begin_data(1));
uint32_t *const pixel_target = reinterpret_cast<uint32_t *>(crt_.begin_data(1));
*pixel_target = border_colour | cram_dot;
crt_->output_level(4);
crt_.output_level(4);
cycles -= 4;
}
if(cycles) {
uint32_t *const pixel_target = reinterpret_cast<uint32_t *>(crt_->begin_data(1));
uint32_t *const pixel_target = reinterpret_cast<uint32_t *>(crt_.begin_data(1));
*pixel_target = border_colour;
crt_->output_level(cycles);
crt_.output_level(cycles);
}
}

View File

@ -42,7 +42,7 @@ class TMS9918: public Base {
void set_tv_standard(TVStandard standard);
/*! Provides the CRT this TMS is connected to. */
Outputs::CRT::CRT *get_crt();
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
/*!
Runs the VCP for the number of cycles indicate; it is an implicit assumption of the code

View File

@ -78,8 +78,8 @@ class Base {
Base(Personality p);
Personality personality_;
std::unique_ptr<Outputs::CRT::CRT> crt_;
const Personality personality_;
Outputs::CRT::CRT crt_;
TVStandard tv_standard_ = TVStandard::NTSC;
// Holds the contents of this VDP's connected DRAM.

View File

@ -112,6 +112,7 @@ class ConcreteMachine:
public:
ConcreteMachine(const Analyser::Static::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
z80_(*this),
vdp_(TI::TMS::TMS9918A),
sn76489_(TI::SN76489::Personality::SN76489, audio_queue_, sn76489_divider),
ay_(audio_queue_),
mixer_(sn76489_, ay_),
@ -170,18 +171,9 @@ class ConcreteMachine:
}
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
vdp_.reset(new TI::TMS::TMS9918(TI::TMS::TMS9918A));
// get_crt()->set_video_signal(Outputs::Display::VideoSignal::Composite);
vdp_.set_scan_target(scan_target);
}
// void close_output() override {
// vdp_.reset();
// }
//
// Outputs::CRT::CRT *get_crt() override {
// return vdp_->get_crt();
// }
Outputs::Speaker::Speaker *get_speaker() override {
return &speaker_;
}
@ -249,9 +241,9 @@ class ConcreteMachine:
switch((address >> 5) & 7) {
case 5:
update_video();
*cycle.value = vdp_->get_register(address);
z80_.set_non_maskable_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
*cycle.value = vdp_.get_register(address);
z80_.set_non_maskable_interrupt_line(vdp_.get_interrupt_line());
time_until_interrupt_ = vdp_.get_time_until_interrupt();
break;
case 7: {
@ -293,9 +285,9 @@ class ConcreteMachine:
case 5:
update_video();
vdp_->set_register(address, *cycle.value);
z80_.set_non_maskable_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
vdp_.set_register(address, *cycle.value);
z80_.set_non_maskable_interrupt_line(vdp_.get_interrupt_line());
time_until_interrupt_ = vdp_.get_time_until_interrupt();
break;
case 7:
@ -366,11 +358,11 @@ class ConcreteMachine:
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
}
inline void update_video() {
vdp_->run_for(time_since_vdp_update_.flush());
vdp_.run_for(time_since_vdp_update_.flush());
}
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
std::unique_ptr<TI::TMS::TMS9918> vdp_;
TI::TMS::TMS9918 vdp_;
Concurrency::DeferringAsyncTaskQueue audio_queue_;
TI::SN76489 sn76489_;

View File

@ -148,6 +148,7 @@ class ConcreteMachine:
public:
ConcreteMachine(const Analyser::Static::MSX::Target &target, const ROMMachine::ROMFetcher &rom_fetcher):
z80_(*this),
vdp_(TI::TMS::TMS9918A),
i8255_(i8255_port_handler_),
ay_(audio_queue_),
audio_toggle_(audio_queue_),
@ -219,17 +220,9 @@ class ConcreteMachine:
}
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
vdp_.reset(new TI::TMS::TMS9918(TI::TMS::TMS9918A));
vdp_.set_scan_target(scan_target);
}
// void close_output() override {
// vdp_.reset();
// }
//
// Outputs::CRT::CRT *get_crt() override {
// return vdp_->get_crt();
// }
Outputs::Speaker::Speaker *get_speaker() override {
return &speaker_;
}
@ -451,10 +444,10 @@ class ConcreteMachine:
case CPU::Z80::PartialMachineCycle::Input:
switch(address & 0xff) {
case 0x98: case 0x99:
vdp_->run_for(time_since_vdp_update_.flush());
*cycle.value = vdp_->get_register(address);
z80_.set_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
vdp_.run_for(time_since_vdp_update_.flush());
*cycle.value = vdp_.get_register(address);
z80_.set_interrupt_line(vdp_.get_interrupt_line());
time_until_interrupt_ = vdp_.get_time_until_interrupt();
break;
case 0xa2:
@ -479,10 +472,10 @@ class ConcreteMachine:
const int port = address & 0xff;
switch(port) {
case 0x98: case 0x99:
vdp_->run_for(time_since_vdp_update_.flush());
vdp_->set_register(address, *cycle.value);
z80_.set_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
vdp_.run_for(time_since_vdp_update_.flush());
vdp_.set_register(address, *cycle.value);
z80_.set_interrupt_line(vdp_.get_interrupt_line());
time_until_interrupt_ = vdp_.get_time_until_interrupt();
break;
case 0xa0: case 0xa1:
@ -555,7 +548,7 @@ class ConcreteMachine:
}
void flush() {
vdp_->run_for(time_since_vdp_update_.flush());
vdp_.run_for(time_since_vdp_update_.flush());
update_audio();
audio_queue_.perform();
}
@ -685,7 +678,7 @@ class ConcreteMachine:
};
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
std::unique_ptr<TI::TMS::TMS9918> vdp_;
TI::TMS::TMS9918 vdp_;
Intel::i8255::i8255<i8255PortHandler> i8255_;
Concurrency::DeferringAsyncTaskQueue audio_queue_;

View File

@ -94,6 +94,7 @@ class ConcreteMachine:
region_(target.region),
paging_scheme_(target.paging_scheme),
z80_(*this),
vdp_(tms_personality_for_model(target.model)),
sn76489_(
(target.model == Target::Model::SG1000) ? TI::SN76489::Personality::SN76489 : TI::SN76489::Personality::SMS,
audio_queue_,
@ -162,29 +163,21 @@ class ConcreteMachine:
}
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
TI::TMS::Personality personality = TI::TMS::TMS9918A;
switch(model_) {
case Target::Model::SG1000: personality = TI::TMS::TMS9918A; break;
case Target::Model::MasterSystem: personality = TI::TMS::SMSVDP; break;
case Target::Model::MasterSystem2: personality = TI::TMS::SMS2VDP; break;
}
vdp_.reset(new TI::TMS::TMS9918(personality));
vdp_->set_tv_standard(
// TI::TMS::Personality personality = TI::TMS::TMS9918A;
// switch(model_) {
// case Target::Model::SG1000: personality = TI::TMS::TMS9918A; break;
// case Target::Model::MasterSystem: personality = TI::TMS::SMSVDP; break;
// case Target::Model::MasterSystem2: personality = TI::TMS::SMS2VDP; break;
// }
// vdp_.reset(new TI::TMS::TMS9918(personality));
vdp_.set_tv_standard(
(region_ == Target::Region::Europe) ?
TI::TMS::TVStandard::PAL : TI::TMS::TVStandard::NTSC);
// get_crt()->set_video_signal(Outputs::Display::VideoSignal::Composite);
time_until_debounce_ = vdp_->get_time_until_line(-1);
time_until_debounce_ = vdp_.get_time_until_line(-1);
}
// void close_output() override {
// vdp_.reset();
// }
//
// Outputs::CRT::CRT *get_crt() override {
// return vdp_->get_crt();
// }
Outputs::Speaker::Speaker *get_speaker() override {
return &speaker_;
}
@ -239,16 +232,16 @@ class ConcreteMachine:
break;
case 0x40:
update_video();
*cycle.value = vdp_->get_current_line();
*cycle.value = vdp_.get_current_line();
break;
case 0x41:
*cycle.value = vdp_->get_latched_horizontal_counter();
*cycle.value = vdp_.get_latched_horizontal_counter();
break;
case 0x80: case 0x81:
update_video();
*cycle.value = vdp_->get_register(address);
z80_.set_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
*cycle.value = vdp_.get_register(address);
z80_.set_interrupt_line(vdp_.get_interrupt_line());
time_until_interrupt_ = vdp_.get_time_until_interrupt();
break;
case 0xc0: {
Joystick *const joypad1 = static_cast<Joystick *>(joysticks_[0].get());
@ -290,7 +283,7 @@ class ConcreteMachine:
// Latch if either TH has newly gone to 1.
if((new_ths^previous_ths)&new_ths) {
update_video();
vdp_->latch_horizontal_counter();
vdp_.latch_horizontal_counter();
}
} break;
case 0x40: case 0x41:
@ -299,9 +292,9 @@ class ConcreteMachine:
break;
case 0x80: case 0x81:
update_video();
vdp_->set_register(address, *cycle.value);
z80_.set_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
vdp_.set_register(address, *cycle.value);
z80_.set_interrupt_line(vdp_.get_interrupt_line());
time_until_interrupt_ = vdp_.get_time_until_interrupt();
break;
case 0xc0:
LOG("TODO: [output] I/O port A/N; " << int(*cycle.value));
@ -337,7 +330,7 @@ class ConcreteMachine:
if(time_until_debounce_ <= HalfCycles(0)) {
z80_.set_non_maskable_interrupt_line(pause_is_pressed_);
update_video();
time_until_debounce_ = vdp_->get_time_until_line(-1);
time_until_debounce_ = vdp_.get_time_until_line(-1);
}
return HalfCycles(0);
@ -395,6 +388,14 @@ class ConcreteMachine:
}
private:
static TI::TMS::Personality tms_personality_for_model(Analyser::Static::Sega::Target::Model model) {
switch(model) {
case Target::Model::SG1000: return TI::TMS::TMS9918A;
case Target::Model::MasterSystem: return TI::TMS::SMSVDP;
case Target::Model::MasterSystem2: return TI::TMS::SMSVDP;
}
}
inline uint8_t get_th_values() {
// Quick not on TH inputs here: if either is setup as an output, then the
// currently output level is returned. Otherwise they're fixed at 1.
@ -410,7 +411,7 @@ class ConcreteMachine:
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
}
inline void update_video() {
vdp_->run_for(time_since_vdp_update_.flush());
vdp_.run_for(time_since_vdp_update_.flush());
}
using Target = Analyser::Static::Sega::Target;
@ -418,7 +419,7 @@ class ConcreteMachine:
Target::Region region_;
Target::PagingScheme paging_scheme_;
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
std::unique_ptr<TI::TMS::TMS9918> vdp_;
TI::TMS::TMS9918 vdp_;
Concurrency::DeferringAsyncTaskQueue audio_queue_;
TI::SN76489 sn76489_;