1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-26 10:29:31 +00:00

Template the TMS on its personality.

Template parameter currently unused, but preparatory to other improvements.
This commit is contained in:
Thomas Harte 2022-12-31 15:08:33 -05:00
parent d79aac3081
commit 7d6eac2895
5 changed files with 43 additions and 19 deletions

View File

@ -110,7 +110,8 @@ Base::Base(Personality p) :
write_pointer_.column = read_pointer_.column + output_lag;
}
TMS9918::TMS9918(Personality p):
template <Personality personality>
TMS9918<personality>::TMS9918(Personality p):
Base(p) {
crt_.set_display_type(Outputs::Display::DisplayType::RGB);
crt_.set_visible_area(Outputs::Display::Rect(0.07f, 0.0375f, 0.875f, 0.875f));
@ -122,7 +123,8 @@ TMS9918::TMS9918(Personality p):
crt_.set_immediate_default_phase(0.85f);
}
void TMS9918::set_tv_standard(TVStandard standard) {
template <Personality personality>
void TMS9918<personality>::set_tv_standard(TVStandard standard) {
tv_standard_ = standard;
switch(standard) {
case TVStandard::PAL:
@ -138,11 +140,13 @@ void TMS9918::set_tv_standard(TVStandard standard) {
}
}
void TMS9918::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
template <Personality personality>
void TMS9918<personality>::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}
Outputs::Display::ScanStatus TMS9918::get_scaled_scan_status() const {
template <Personality personality>
Outputs::Display::ScanStatus TMS9918<personality>::get_scaled_scan_status() const {
// The input was scaled by 3/4 to convert half cycles to internal ticks,
// so undo that and also allow for: (i) the multiply by 4 that it takes
// to reach the CRT; and (ii) the fact that the half-cycles value was scaled,
@ -150,11 +154,13 @@ Outputs::Display::ScanStatus TMS9918::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status() * (4.0f / (3.0f * 8.0f));
}
void TMS9918::set_display_type(Outputs::Display::DisplayType display_type) {
template <Personality personality>
void TMS9918<personality>::set_display_type(Outputs::Display::DisplayType display_type) {
crt_.set_display_type(display_type);
}
Outputs::Display::DisplayType TMS9918::get_display_type() const {
template <Personality personality>
Outputs::Display::DisplayType TMS9918<personality>::get_display_type() const {
return crt_.get_display_type();
}
@ -193,7 +199,8 @@ void Base::posit_sprite(LineBuffer &buffer, int sprite_number, int sprite_positi
++buffer.active_sprite_slot;
}
void TMS9918::run_for(const HalfCycles cycles) {
template <Personality personality>
void TMS9918<personality>::run_for(const HalfCycles cycles) {
// As specific as I've been able to get:
// Scanline time is always 228 cycles.
// PAL output is 313 lines total. NTSC output is 262 lines total.
@ -532,7 +539,8 @@ void Base::output_border(int cycles, uint32_t cram_dot) {
}
}
void TMS9918::write(int address, uint8_t value) {
template <Personality personality>
void TMS9918<personality>::write(int address, uint8_t value) {
// Writes to address 0 are writes to the video RAM. Store
// the value and return.
if(!(address & 1)) {
@ -662,7 +670,8 @@ void TMS9918::write(int address, uint8_t value) {
}
}
uint8_t TMS9918::get_current_line() {
template <Personality personality>
uint8_t TMS9918<personality>::get_current_line() {
// Determine the row to return.
constexpr int row_change_position = 63; // This is the proper Master System value; substitute if any other VDPs turn out to have this functionality.
int source_row =
@ -696,7 +705,8 @@ uint8_t TMS9918::get_current_line() {
return uint8_t(source_row);
}
uint8_t TMS9918::get_latched_horizontal_counter() {
template <Personality personality>
uint8_t TMS9918<personality>::get_latched_horizontal_counter() {
// Translate from internal numbering, which puts pixel output
// in the final 256 pixels of 342, to the public numbering,
// which makes the 256 pixels the first 256 spots, but starts
@ -706,11 +716,13 @@ uint8_t TMS9918::get_latched_horizontal_counter() {
return uint8_t(public_counter >> 1);
}
void TMS9918::latch_horizontal_counter() {
template <Personality personality>
void TMS9918<personality>::latch_horizontal_counter() {
latched_column_ = write_pointer_.column;
}
uint8_t TMS9918::read(int address) {
template <Personality personality>
uint8_t TMS9918<personality>::read(int address) {
write_phase_ = false;
// Reads from address 0 read video RAM, via the read-ahead buffer.
@ -732,7 +744,8 @@ HalfCycles Base::half_cycles_before_internal_cycles(int internal_cycles) {
return HalfCycles(((internal_cycles << 2) + (2 - cycles_error_)) / 3);
}
HalfCycles TMS9918::get_next_sequence_point() {
template <Personality personality>
HalfCycles TMS9918<personality>::get_next_sequence_point() {
if(!generate_interrupts_ && !enable_line_interrupts_) return HalfCycles::max();
if(get_interrupt_line()) return HalfCycles::max();
@ -786,7 +799,8 @@ HalfCycles TMS9918::get_next_sequence_point() {
return half_cycles_before_internal_cycles(std::min(local_cycles_until_line_interrupt, time_until_frame_interrupt));
}
HalfCycles TMS9918::get_time_until_line(int line) {
template <Personality personality>
HalfCycles TMS9918<personality>::get_time_until_line(int line) {
if(line < 0) line += mode_timing_.total_lines;
int cycles_to_next_interrupt_threshold = mode_timing_.line_interrupt_position - write_pointer_.column;
@ -803,7 +817,8 @@ HalfCycles TMS9918::get_time_until_line(int line) {
return half_cycles_before_internal_cycles(cycles_to_next_interrupt_threshold + (line - line_of_next_interrupt_threshold)*342);
}
bool TMS9918::get_interrupt_line() {
template <Personality personality>
bool TMS9918<personality>::get_interrupt_line() {
return ((status_ & StatusInterrupt) && generate_interrupts_) || (enable_line_interrupts_ && line_interrupt_pending_);
}
@ -1074,3 +1089,11 @@ void Base::draw_sms(int start, int end, uint32_t cram_dot) {
}
}
}
template class TI::TMS::TMS9918<Personality::TMS9918A>;
template class TI::TMS::TMS9918<Personality::V9938>;
template class TI::TMS::TMS9918<Personality::V9958>;
template class TI::TMS::TMS9918<Personality::SMSVDP>;
template class TI::TMS::TMS9918<Personality::SMS2VDP>;
template class TI::TMS::TMS9918<Personality::GGVDP>;
template class TI::TMS::TMS9918<Personality::MDVDP>;

View File

@ -48,7 +48,7 @@ namespace TMS {
These chips have only one non-on-demand interaction with the outside world: an interrupt line.
See get_time_until_interrupt and get_interrupt_line for asynchronous operation options.
*/
class TMS9918: public Base {
template <Personality personality> class TMS9918: public Base {
public:
/*!
Constructs an instance of the drive controller that behaves according to personality @c p.

View File

@ -379,7 +379,7 @@ class ConcreteMachine:
}
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
JustInTimeActor<TI::TMS::TMS9918> vdp_;
JustInTimeActor<TI::TMS::TMS9918<TI::TMS::Personality::TMS9918A>> vdp_;
Concurrency::AsyncTaskQueue<false> audio_queue_;
TI::SN76489 sn76489_;

View File

@ -744,7 +744,7 @@ class ConcreteMachine:
};
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
JustInTimeActor<TI::TMS::TMS9918> vdp_;
JustInTimeActor<TI::TMS::TMS9918<TI::TMS::Personality::TMS9918A>> vdp_;
Intel::i8255::i8255<i8255PortHandler> i8255_;
Concurrency::AsyncTaskQueue<false> audio_queue_;

View File

@ -431,6 +431,7 @@ class ConcreteMachine:
}
private:
// TODO: incorporate this into the VDP declaration.
static TI::TMS::Personality tms_personality_for_model(Analyser::Static::Sega::Target::Model model) {
switch(model) {
default:
@ -485,7 +486,7 @@ class ConcreteMachine:
const Target::Region region_;
const Target::PagingScheme paging_scheme_;
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
JustInTimeActor<TI::TMS::TMS9918> vdp_;
JustInTimeActor<TI::TMS::TMS9918<TI::TMS::Personality::SMSVDP>> vdp_; // TODO.
Concurrency::AsyncTaskQueue<false> audio_queue_;
TI::SN76489 sn76489_;