mirror of
https://github.com/TomHarte/CLK.git
synced 2024-10-07 21:57:46 +00:00
Implements video position feedback.
At a substantial performance cost for now, but I'll worry about that once things are working.
This commit is contained in:
parent
0ad88508f7
commit
41740fb45e
@ -40,7 +40,7 @@ class ConcreteMachine:
|
|||||||
mc68000_(*this),
|
mc68000_(*this),
|
||||||
video_(ram_.data()),
|
video_(ram_.data()),
|
||||||
via_(via_port_handler_),
|
via_(via_port_handler_),
|
||||||
via_port_handler_(*this, clock_, keyboard_),
|
via_port_handler_(*this, clock_, keyboard_, video_),
|
||||||
iwm_(CLOCK_RATE) {
|
iwm_(CLOCK_RATE) {
|
||||||
|
|
||||||
// Grab a copy of the ROM and convert it into big-endian data.
|
// Grab a copy of the ROM and convert it into big-endian data.
|
||||||
@ -70,7 +70,7 @@ class ConcreteMachine:
|
|||||||
using Microcycle = CPU::MC68000::Microcycle;
|
using Microcycle = CPU::MC68000::Microcycle;
|
||||||
|
|
||||||
HalfCycles perform_bus_operation(const Microcycle &cycle, int is_supervisor) {
|
HalfCycles perform_bus_operation(const Microcycle &cycle, int is_supervisor) {
|
||||||
time_since_video_update_ += cycle.length;
|
// time_since_video_update_ += cycle.length;
|
||||||
time_since_iwm_update_ += cycle.length;
|
time_since_iwm_update_ += cycle.length;
|
||||||
|
|
||||||
// The VIA runs at one-tenth of the 68000's clock speed, in sync with the E clock.
|
// The VIA runs at one-tenth of the 68000's clock speed, in sync with the E clock.
|
||||||
@ -100,6 +100,10 @@ class ConcreteMachine:
|
|||||||
via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::Two, false);
|
via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::Two, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the video. TODO: only on demand.
|
||||||
|
video_.run_for(cycle.length);
|
||||||
|
via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, video_.vsync());
|
||||||
|
|
||||||
// Update interrupt input. TODO: move this into a VIA/etc delegate callback?
|
// Update interrupt input. TODO: move this into a VIA/etc delegate callback?
|
||||||
mc68000_.set_interrupt_level( (via_.get_interrupt_line() ? 1 : 0) );
|
mc68000_.set_interrupt_level( (via_.get_interrupt_line() ? 1 : 0) );
|
||||||
|
|
||||||
@ -140,7 +144,8 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if(cycle.operation & Microcycle::Read) {
|
if(cycle.operation & Microcycle::Read) {
|
||||||
cycle.value->halves.low = 0xff;
|
printf("Unrecognised read %06x\n", *cycle.address & 0xffffff);
|
||||||
|
cycle.value->halves.low = 0x00;
|
||||||
if(cycle.operation & Microcycle::SelectWord) cycle.value->halves.high = 0xff;
|
if(cycle.operation & Microcycle::SelectWord) cycle.value->halves.high = 0xff;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -211,7 +216,7 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
video_.run_for(time_since_video_update_.flush());
|
// video_.run_for(time_since_video_update_.flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_rom_is_overlay(bool rom_is_overlay) {
|
void set_rom_is_overlay(bool rom_is_overlay) {
|
||||||
@ -225,8 +230,8 @@ class ConcreteMachine:
|
|||||||
private:
|
private:
|
||||||
class VIAPortHandler: public MOS::MOS6522::PortHandler {
|
class VIAPortHandler: public MOS::MOS6522::PortHandler {
|
||||||
public:
|
public:
|
||||||
VIAPortHandler(ConcreteMachine &machine, RealTimeClock &clock, Keyboard &keyboard) :
|
VIAPortHandler(ConcreteMachine &machine, RealTimeClock &clock, Keyboard &keyboard, Video &video) :
|
||||||
machine_(machine), clock_(clock), keyboard_(keyboard) {}
|
machine_(machine), clock_(clock), keyboard_(keyboard), video_(video) {}
|
||||||
|
|
||||||
using Port = MOS::MOS6522::Port;
|
using Port = MOS::MOS6522::Port;
|
||||||
using Line = MOS::MOS6522::Line;
|
using Line = MOS::MOS6522::Line;
|
||||||
@ -275,11 +280,13 @@ class ConcreteMachine:
|
|||||||
switch(port) {
|
switch(port) {
|
||||||
case Port::A:
|
case Port::A:
|
||||||
// printf("6522 r A\n");
|
// printf("6522 r A\n");
|
||||||
return 0xff;
|
return 0x00; // TODO: b7 = SCC wait/request
|
||||||
|
|
||||||
case Port::B:
|
case Port::B:
|
||||||
// printf("6522 r B\n");
|
return
|
||||||
return (clock_.get_data() ? 0x02 : 0x00);
|
(clock_.get_data() ? 0x02 : 0x00) |
|
||||||
|
(video_.is_outputting() ? 0x00 : 0x40);
|
||||||
|
// TODO: mouse button, y2, x2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,6 +306,7 @@ class ConcreteMachine:
|
|||||||
ConcreteMachine &machine_;
|
ConcreteMachine &machine_;
|
||||||
RealTimeClock &clock_;
|
RealTimeClock &clock_;
|
||||||
Keyboard &keyboard_;
|
Keyboard &keyboard_;
|
||||||
|
Video &video_;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<uint16_t, 32*1024> rom_;
|
std::array<uint16_t, 32*1024> rom_;
|
||||||
@ -318,7 +326,8 @@ class ConcreteMachine:
|
|||||||
HalfCycles via_clock_;
|
HalfCycles via_clock_;
|
||||||
HalfCycles real_time_clock_;
|
HalfCycles real_time_clock_;
|
||||||
HalfCycles keyboard_clock_;
|
HalfCycles keyboard_clock_;
|
||||||
HalfCycles time_since_video_update_;
|
HalfCycles video_clock_;
|
||||||
|
// HalfCycles time_since_video_update_;
|
||||||
HalfCycles time_since_iwm_update_;
|
HalfCycles time_since_iwm_update_;
|
||||||
|
|
||||||
bool ROM_is_overlay_ = true;
|
bool ROM_is_overlay_ = true;
|
||||||
|
@ -17,6 +17,8 @@ namespace {
|
|||||||
const HalfCycles line_length(704);
|
const HalfCycles line_length(704);
|
||||||
const int number_of_lines = 370;
|
const int number_of_lines = 370;
|
||||||
const HalfCycles frame_length(line_length * HalfCycles(number_of_lines));
|
const HalfCycles frame_length(line_length * HalfCycles(number_of_lines));
|
||||||
|
const int sync_start = 36;
|
||||||
|
const int sync_end = 38;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +46,6 @@ void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Video::run_for(HalfCycles duration) {
|
void Video::run_for(HalfCycles duration) {
|
||||||
const int sync_start = 36;
|
|
||||||
const int sync_end = 38;
|
|
||||||
|
|
||||||
// The number of HalfCycles is literally the number of pixel clocks to move through,
|
// The number of HalfCycles is literally the number of pixel clocks to move through,
|
||||||
// since pixel output occurs at twice the processor clock. So divide by 16 to get
|
// since pixel output occurs at twice the processor clock. So divide by 16 to get
|
||||||
@ -145,6 +145,18 @@ void Video::run_for(HalfCycles duration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Video::vsync() {
|
||||||
|
const int line = (frame_position_ / line_length).as_int();
|
||||||
|
return line >= 353 && line < 356;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Video::is_outputting() {
|
||||||
|
const int column = (frame_position_ % line_length).as_int() >> 4;
|
||||||
|
const int line = (frame_position_ / line_length).as_int();
|
||||||
|
return line < 342 && column < 32;
|
||||||
|
}
|
||||||
|
|
||||||
void Video::set_use_alternate_screen_buffer(bool use_alternate_screen_buffer) {
|
void Video::set_use_alternate_screen_buffer(bool use_alternate_screen_buffer) {
|
||||||
use_alternate_screen_buffer_ = use_alternate_screen_buffer;
|
use_alternate_screen_buffer_ = use_alternate_screen_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ class Video {
|
|||||||
void set_use_alternate_screen_buffer(bool use_alternate_screen_buffer);
|
void set_use_alternate_screen_buffer(bool use_alternate_screen_buffer);
|
||||||
|
|
||||||
// TODO: feedback on blanks and syncs.
|
// TODO: feedback on blanks and syncs.
|
||||||
|
bool vsync();
|
||||||
|
bool is_outputting();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Outputs::CRT::CRT crt_;
|
Outputs::CRT::CRT crt_;
|
||||||
|
Loading…
Reference in New Issue
Block a user