1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-16 18:30:32 +00:00

Implements line querying and most of line interrupts.

This commit is contained in:
Thomas Harte 2018-10-04 22:50:35 -04:00
parent aac97a8983
commit 7830cda912
4 changed files with 86 additions and 15 deletions

View File

@ -61,6 +61,10 @@ Base::Base(Personality p) :
ram_.resize(192 * 1024);
break;
}
if(is_sega_vdp(personality_)) {
mode_timing_.line_interrupt_position = 15;
}
}
TMS9918::TMS9918(Personality p):
@ -292,9 +296,6 @@ void TMS9918::run_for(const HalfCycles cycles) {
// -----------------
column_ = end_column; // column_ is now the column that has been reached in this line.
int_cycles -= cycles_left; // Count down duration to run for.
/*
// --------------
@ -421,6 +422,26 @@ void TMS9918::run_for(const HalfCycles cycles) {
}*/
if(column_ < mode_timing_.line_interrupt_position && end_column >= mode_timing_.line_interrupt_position) {
if(row_ <= mode_timing_.pixel_lines) {
--line_interrupt_counter;
if(line_interrupt_counter == 0xff) {
// line_interrupt_pending_ = true;
line_interrupt_counter = line_interrupt_target;
}
} else {
line_interrupt_counter = line_interrupt_target;
}
}
// -------------
// Advance time.
// -------------
column_ = end_column; // column_ is now the column that has been reached in this line.
int_cycles -= cycles_left; // Count down duration to run for.
// -----------------------------------
// Prepare for next line, potentially.
@ -513,7 +534,7 @@ void TMS9918::set_register(int address, uint8_t value) {
master_system_.vertical_scroll_lock = !!(low_write_ & 0x80);
master_system_.horizontal_scroll_lock = !!(low_write_ & 0x40);
master_system_.hide_left_column = !!(low_write_ & 0x20);
master_system_.enable_line_interrupts = !!(low_write_ & 0x10);
enable_line_interrupts_ = !!(low_write_ & 0x10);
master_system_.shift_sprites_8px_left = !!(low_write_ & 0x08);
master_system_.mode4_enable = !!(low_write_ & 0x04);
}
@ -569,6 +590,16 @@ void TMS9918::set_register(int address, uint8_t value) {
master_system_.vertical_scroll = low_write_;
}
break;
case 10:
if(is_sega_vdp(personality_)) {
line_interrupt_target = value;
}
break;
default:
printf("%d to %d\n", low_write_, value);
break;
}
} else {
// This is a write to the RAM pointer.
@ -581,6 +612,10 @@ void TMS9918::set_register(int address, uint8_t value) {
}
}
uint8_t TMS9918::get_current_line() {
return static_cast<uint8_t>(row_);
}
uint8_t TMS9918::get_register(int address) {
write_phase_ = false;
@ -595,21 +630,44 @@ uint8_t TMS9918::get_register(int address) {
// Reads from address 1 get the status register.
uint8_t result = status_;
status_ &= ~(StatusInterrupt | StatusFifthSprite | StatusSpriteCollision);
line_interrupt_pending_ = false;
return result;
}
HalfCycles TMS9918::get_time_until_interrupt() {
// TODO: line interrupts.
if(!generate_interrupts_) return HalfCycles(-1);
if(!generate_interrupts_ && !enable_line_interrupts_) return HalfCycles(-1);
if(get_interrupt_line()) return HalfCycles(0);
// Calculate the amount of time until the next end-of-frame interrupt.
const int half_cycles_per_frame = mode_timing_.total_lines * 228 * 2;
int half_cycles_remaining = (192 * 228 * 2 + half_cycles_per_frame - half_cycles_into_frame_.as_int()) % half_cycles_per_frame;
return HalfCycles(half_cycles_remaining ? half_cycles_remaining : half_cycles_per_frame);
const int half_cycles_remaining = (192 * 228 * 2 + half_cycles_per_frame - half_cycles_into_frame_.as_int()) % half_cycles_per_frame;
const auto time_until_frame_interrupt = HalfCycles(half_cycles_remaining ? half_cycles_remaining : half_cycles_per_frame);
// Calculate the number of times the line interrupt position will be decremented this frame.
// return HalfCycles(20);
/* auto time_until_line_count = mode_timing_.line_interrupt_position - row_;
auto decrements_left_this_frame = mode_timing_.pixel_lines - row_;
if(time_until_line_count > 0) {
++decrements_left_this_frame;
}
// If that's enough to underflow the line counter, there's the next interupt.
HalfCycles time_until_line_interrupt;
if(decrements_left_this_frame >= line_interrupt_counter+1) {
time_until_line_interrupt = HalfCycles
}
if(!enable_line_interrupts_) {
return time_until_frame_interrupt;
} else if(!generate_interrupts_) {
}*/
return time_until_frame_interrupt;
}
bool TMS9918::get_interrupt_line() {
return (status_ & StatusInterrupt) && generate_interrupts_;
return ((status_ & StatusInterrupt) && generate_interrupts_) || (enable_line_interrupts_ && line_interrupt_pending_);
}
// MARK: -

View File

@ -63,6 +63,9 @@ class TMS9918: public Base {
/*! Gets a register value. */
uint8_t get_register(int address);
/*! Gets the current scan line; provided by the Master System only. */
uint8_t get_current_line();
/*!
Returns the amount of time until get_interrupt_line would next return true if
there are no interceding calls to set_register or get_register.

View File

@ -153,8 +153,17 @@ class Base {
// if sprites beyond this number should be visible
// then the appropriate status information will be set.
int maximum_visible_sprites = 4;
//
int end_of_frame_interrupt_position = 342;
int line_interrupt_position = -1;
} mode_timing_;
uint8_t line_interrupt_target = 0;
uint8_t line_interrupt_counter = 0;
bool enable_line_interrupts_ = false;
bool line_interrupt_pending_ = false;
// The line mode describes the proper timing diagram for the current line.
enum class LineMode {
Text,
@ -174,7 +183,6 @@ class Base {
bool vertical_scroll_lock = false;
bool horizontal_scroll_lock = false;
bool hide_left_column = false;
bool enable_line_interrupts = false;
bool shift_sprites_8px_left = false;
bool mode4_enable = false;
uint8_t horizontal_scroll = 0;
@ -673,7 +681,7 @@ class Base {
background_render_block(91, 12);
background_render_block(107, 16);
background_render_block(123, 20);
background_render_block(139, 24);
background_render_block(139, 24); // TODO: this and the next one should ignore master_system_.vertical_scroll.
background_render_block(156, 28);
return;

View File

@ -163,8 +163,10 @@ class ConcreteMachine:
case CPU::Z80::PartialMachineCycle::Write:
if(address >= 0xfffd && cartridge_.size() > 48*1024) {
paging_registers_[address - 0xfffd] = *cycle.value;
page_cartridge();
if(paging_registers_[address - 0xfffd] != *cycle.value) {
paging_registers_[address - 0xfffd] = *cycle.value;
page_cartridge();
}
}
else if(write_pointers_[address >> 10]) write_pointers_[address >> 10][address & 1023] = *cycle.value;
break;
@ -180,8 +182,8 @@ class ConcreteMachine:
*cycle.value = 0xff;
break;
case 0x40: case 0x41:
printf("TODO: [input] get current line\n");
*cycle.value = 0xff;
update_video();
*cycle.value = vdp_->get_current_line();
break;
case 0x80: case 0x81:
update_video();