mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-19 07:31:15 +00:00
Template the TMS on its personality.
Template parameter currently unused, but preparatory to other improvements.
This commit is contained in:
parent
d79aac3081
commit
7d6eac2895
@ -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>;
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
|
@ -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_;
|
||||
|
@ -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_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user