1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-21 21:33:54 +00:00

Sub in basic transliteration of hoglet's FPGA.

This commit is contained in:
Thomas Harte 2024-09-06 20:21:46 -04:00
parent aab2dd68b6
commit 59530a12fd
3 changed files with 93 additions and 50 deletions

View File

@ -683,7 +683,7 @@ template <bool has_scsi_bus> class ConcreteMachine:
speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide(Cycles(SoundGenerator::clock_rate_divider)));
}
inline void signal_interrupt(Interrupt interrupt) {
inline void signal_interrupt(uint8_t interrupt) {
if(!interrupt) {
return;
}

View File

@ -230,54 +230,97 @@ Outputs::Display::DisplayType VideoOutput::get_display_type() const {
// }
//}
Electron::Interrupt VideoOutput::run_for(const Cycles cycles) {
Electron::Interrupt interrupts{};
// int number_of_cycles = int(cycles.as_integral());
// const auto start_position = output_position_;
// output_position_ = (output_position_ + number_of_cycles) % cycles_per_frame;
//
// const auto test_range = [&](int start, int end) {
// if(
// (start < real_time_clock_interrupt_1 && end >= real_time_clock_interrupt_1) ||
// (start < real_time_clock_interrupt_2 && end >= real_time_clock_interrupt_2)
// ) {
// interrupts_ = Electron::Interrupt(interrupts_ | Electron::Interrupt::RealTimeClock);
// }
//
// if(
// (start < display_end_interrupt_1 && end >= display_end_interrupt_1) ||
// (start < display_end_interrupt_2 && end >= display_end_interrupt_2)
// ) {
// interrupts_ = Electron::Interrupt(interrupts_ | Electron::Interrupt::DisplayEnd);
// }
// };
//
// if(output_position_ >= start_position) {
// test_range(start_position, output_position_);
// } else {
// test_range(start_position, cycles_per_frame);
// test_range(0, output_position_);
// }
//
// while(number_of_cycles) {
// int draw_action_length = screen_map_[screen_map_pointer_].length;
// int time_left_in_action = std::min(number_of_cycles, draw_action_length - cycles_into_draw_action_);
// if(screen_map_[screen_map_pointer_].type == DrawAction::Pixels) output_pixels(time_left_in_action);
//
// number_of_cycles -= time_left_in_action;
// cycles_into_draw_action_ += time_left_in_action;
// if(cycles_into_draw_action_ == draw_action_length) {
// switch(screen_map_[screen_map_pointer_].type) {
// case DrawAction::Sync: crt_.output_sync(draw_action_length * crt_cycles_multiplier); break;
// case DrawAction::ColourBurst: crt_.output_default_colour_burst(draw_action_length * crt_cycles_multiplier); break;
// case DrawAction::Blank: crt_.output_blank(draw_action_length * crt_cycles_multiplier); break;
// case DrawAction::Pixels: end_pixel_line(); break;
// }
// screen_map_pointer_ = (screen_map_pointer_ + 1) % screen_map_.size();
// cycles_into_draw_action_ = 0;
// if(screen_map_[screen_map_pointer_].type == DrawAction::Pixels) start_pixel_line();
// }
// }
uint8_t VideoOutput::run_for(const Cycles cycles) {
uint8_t interrupts{};
int number_of_cycles = cycles.as<int>();
while(number_of_cycles--) {
// Horizontal and vertical counter updates.
const bool is_v_end = v_count == v_total();
h_count += 8;
if(h_count == h_total) {
h_count = 0;
++v_count;
if(is_v_end) {
v_count = 0;
field = !field;
}
}
// Test for interrupts.
if(v_count == v_rtc && ((!field && !h_count) || (field && h_count == h_half))) {
interrupts |= static_cast<uint8_t>(Interrupt::RealTimeClock);
}
if(h_count == hsync_start && ((v_count == v_disp_gph && !mode_text) or (v_count == v_disp_txt && mode_text))) {
interrupts |= static_cast<uint8_t>(Interrupt::DisplayEnd);
}
// Update syncs.
if(!field) {
if(!h_count && v_count == vsync_start) {
vsync_int = true;
} else if(h_count == h_half && v_count == vsync_end) {
vsync_int = false;
}
} else {
if(h_count == h_half && v_count == vsync_start) {
vsync_int = true;
} else if(!h_count && v_count == vsync_end + 1) {
vsync_int = false;
}
}
const auto h_sync_last = hsync_int;
if(h_count == hsync_start) {
hsync_int = true;
} else if(h_count == hsync_end) {
hsync_int = false;
}
// Update character row on the trailing edge of hsync.
if(h_count == hsync_end) {
if(is_v_end) {
char_row = 0;
} else {
char_row = last_line() ? 0 : char_row + 1;
}
}
// Disable the top bit of the char_row counter outside of text mode.
if(!mode_text) {
char_row &= 7;
}
// Latch video address at frame start.
if(h_count == h_reset_addr && is_v_end) {
row_addr = byte_addr = screen_base;
}
// Copy byte_addr back into row_addr if a new character row has begun.
if(hsync_int) {
if(last_line()) {
row_addr = byte_addr;
} else {
byte_addr = row_addr;
}
}
// Increment the byte address across the line.
// (slghtly pained logic here because the input clock is still at the pixel rate, not the byte rate)
if(h_count < h_active) {
if(
(!mode_40 && !(h_count & 0x7)) ||
(mode_40 && ((h_count & 0xf) == 0x8))
) {
byte_addr += 8;
if(!(byte_addr & 0b0111'1000'0000'0000)) {
byte_addr = mode_base | (byte_addr & 0x0000'0111'1111'1111);
}
}
}
}
return interrupts;
}

View File

@ -47,7 +47,7 @@ class VideoOutput {
/// Produces the next @c cycles of video output.
///
/// @returns a bit mask of all interrupts triggered.
Electron::Interrupt run_for(const Cycles cycles);
uint8_t run_for(const Cycles cycles);
/// @returns The number of 2Mhz cycles that will pass before completion of an attempted
/// IO [/1Mhz] access that is first signalled in the upcoming cycle.