mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
Introduces horizontal counter latching and reading.
Then makes a new guess at frame IRQ position. But gets it wrong. Hmmm.
This commit is contained in:
parent
9a933993f5
commit
52e02db5c8
@ -526,8 +526,9 @@ uint8_t TMS9918::get_current_line() {
|
|||||||
int source_row = (column_ < mode_timing_.line_interrupt_position) ? (row_ + mode_timing_.total_lines - 1)%mode_timing_.total_lines : row_;
|
int source_row = (column_ < mode_timing_.line_interrupt_position) ? (row_ + mode_timing_.total_lines - 1)%mode_timing_.total_lines : row_;
|
||||||
// This assumes NTSC 192-line. TODO: other modes.
|
// This assumes NTSC 192-line. TODO: other modes.
|
||||||
if(source_row >= 0xdb) source_row -= 6;
|
if(source_row >= 0xdb) source_row -= 6;
|
||||||
|
|
||||||
|
// printf("Current row: %d -> %d\n", row_, source_row);
|
||||||
return static_cast<uint8_t>(source_row);
|
return static_cast<uint8_t>(source_row);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: Full proper sequence of current lines:
|
TODO: Full proper sequence of current lines:
|
||||||
@ -539,6 +540,21 @@ uint8_t TMS9918::get_current_line() {
|
|||||||
PAL 256x224 00-FF, 00-02, CA-FF
|
PAL 256x224 00-FF, 00-02, CA-FF
|
||||||
PAL 256x240 00-FF, 00-0A, D2-FF
|
PAL 256x240 00-FF, 00-0A, D2-FF
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TMS9918::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
|
||||||
|
// counting at -48, and returns only the top 8 bits of the number.
|
||||||
|
int public_counter = latched_column_ - 86;
|
||||||
|
if(public_counter < -48) public_counter += 342;
|
||||||
|
return uint8_t(public_counter >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TMS9918::latch_horizontal_counter() {
|
||||||
|
latched_column_ = column_;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t TMS9918::get_register(int address) {
|
uint8_t TMS9918::get_register(int address) {
|
||||||
write_phase_ = false;
|
write_phase_ = false;
|
||||||
|
@ -66,6 +66,10 @@ class TMS9918: public Base {
|
|||||||
/*! Gets the current scan line; provided by the Master System only. */
|
/*! Gets the current scan line; provided by the Master System only. */
|
||||||
uint8_t get_current_line();
|
uint8_t get_current_line();
|
||||||
|
|
||||||
|
uint8_t get_latched_horizontal_counter();
|
||||||
|
|
||||||
|
void latch_horizontal_counter();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the amount of time until get_interrupt_line would next return true if
|
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.
|
there are no interceding calls to set_register or get_register.
|
||||||
|
@ -106,7 +106,7 @@ class Base {
|
|||||||
uint8_t background_colour_ = 0;
|
uint8_t background_colour_ = 0;
|
||||||
|
|
||||||
// Internal mechanisms for position tracking.
|
// Internal mechanisms for position tracking.
|
||||||
int column_ = 0, row_ = 0;
|
int column_ = 0, row_ = 0, latched_column_ = 0;
|
||||||
int cycles_error_ = 0;
|
int cycles_error_ = 0;
|
||||||
HalfCycles half_cycles_before_internal_cycles(int internal_cycles);
|
HalfCycles half_cycles_before_internal_cycles(int internal_cycles);
|
||||||
|
|
||||||
@ -156,8 +156,8 @@ class Base {
|
|||||||
// Set the position, in cycles, of the two interrupts,
|
// Set the position, in cycles, of the two interrupts,
|
||||||
// within a line.
|
// within a line.
|
||||||
struct {
|
struct {
|
||||||
int column = 342;
|
int column = 4;
|
||||||
int row = 191;
|
int row = 193;
|
||||||
} end_of_frame_interrupt_position;
|
} end_of_frame_interrupt_position;
|
||||||
int line_interrupt_position = -1;
|
int line_interrupt_position = -1;
|
||||||
|
|
||||||
|
@ -184,10 +184,13 @@ class ConcreteMachine:
|
|||||||
printf("TODO: [input] I/O port control\n");
|
printf("TODO: [input] I/O port control\n");
|
||||||
*cycle.value = 0xff;
|
*cycle.value = 0xff;
|
||||||
break;
|
break;
|
||||||
case 0x40: case 0x41:
|
case 0x40:
|
||||||
update_video();
|
update_video();
|
||||||
*cycle.value = vdp_->get_current_line();
|
*cycle.value = vdp_->get_current_line();
|
||||||
break;
|
break;
|
||||||
|
case 0x41:
|
||||||
|
*cycle.value = vdp_->get_latched_horizontal_counter();
|
||||||
|
break;
|
||||||
case 0x80: case 0x81:
|
case 0x80: case 0x81:
|
||||||
update_video();
|
update_video();
|
||||||
*cycle.value = vdp_->get_register(address);
|
*cycle.value = vdp_->get_register(address);
|
||||||
@ -201,7 +204,11 @@ class ConcreteMachine:
|
|||||||
} break;
|
} break;
|
||||||
case 0xc1: {
|
case 0xc1: {
|
||||||
Joystick *const joypad2 = static_cast<Joystick *>(joysticks_[1].get());
|
Joystick *const joypad2 = static_cast<Joystick *>(joysticks_[1].get());
|
||||||
*cycle.value = (joypad2->get_state() >> 2) | 0xf;
|
|
||||||
|
*cycle.value =
|
||||||
|
(joypad2->get_state() >> 2) |
|
||||||
|
0x30 |
|
||||||
|
get_th_values();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -219,9 +226,20 @@ class ConcreteMachine:
|
|||||||
page_cartridge();
|
page_cartridge();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01: {
|
||||||
printf("TODO: [output] I/O port control\n");
|
// A programmer can force the TH lines to 0 here,
|
||||||
break;
|
// causing a phoney lightgun latch, so check for any
|
||||||
|
// discontinuity in TH inputs.
|
||||||
|
const auto previous_ths = get_th_values();
|
||||||
|
io_port_control_ = *cycle.value;
|
||||||
|
const auto new_ths = get_th_values();
|
||||||
|
|
||||||
|
// Latch if either TH has newly gone to 1.
|
||||||
|
if((new_ths^previous_ths)&new_ths) {
|
||||||
|
update_video();
|
||||||
|
vdp_->latch_horizontal_counter();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case 0x40: case 0x41:
|
case 0x40: case 0x41:
|
||||||
update_audio();
|
update_audio();
|
||||||
sn76489_.set_register(*cycle.value);
|
sn76489_.set_register(*cycle.value);
|
||||||
@ -233,7 +251,7 @@ class ConcreteMachine:
|
|||||||
time_until_interrupt_ = vdp_->get_time_until_interrupt();
|
time_until_interrupt_ = vdp_->get_time_until_interrupt();
|
||||||
break;
|
break;
|
||||||
case 0xc0:
|
case 0xc0:
|
||||||
// printf("TODO: [output] I/O port A/N [%02x]\n", *cycle.value);
|
printf("TODO: [output] I/O port A/N [%02x]\n", *cycle.value);
|
||||||
break;
|
break;
|
||||||
case 0xc1:
|
case 0xc1:
|
||||||
printf("TODO: [output] I/O port B/misc\n");
|
printf("TODO: [output] I/O port B/misc\n");
|
||||||
@ -274,6 +292,17 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
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.
|
||||||
|
return
|
||||||
|
static_cast<uint8_t>(
|
||||||
|
((io_port_control_ & 0x02) << 5) | ((io_port_control_&0x20) << 1) |
|
||||||
|
((io_port_control_ & 0x08) << 4) | (io_port_control_&0x80)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
inline void update_audio() {
|
inline void update_audio() {
|
||||||
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
|
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
|
||||||
}
|
}
|
||||||
@ -299,6 +328,8 @@ class ConcreteMachine:
|
|||||||
uint8_t bios_[8*1024];
|
uint8_t bios_[8*1024];
|
||||||
std::vector<uint8_t> cartridge_;
|
std::vector<uint8_t> cartridge_;
|
||||||
|
|
||||||
|
uint8_t io_port_control_ = 0x0f;
|
||||||
|
|
||||||
// The memory map has a 1kb granularity; this is determined by the SG1000's 1kb of RAM.
|
// The memory map has a 1kb granularity; this is determined by the SG1000's 1kb of RAM.
|
||||||
const uint8_t *read_pointers_[64];
|
const uint8_t *read_pointers_[64];
|
||||||
uint8_t *write_pointers_[64];
|
uint8_t *write_pointers_[64];
|
||||||
|
Loading…
Reference in New Issue
Block a user