mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-24 12:30:17 +00:00
Merge pull request #1245 from TomHarte/MDANoCursor
MDA: implement no cursor, blink attribute.
This commit is contained in:
commit
e9420fc48d
@ -23,6 +23,10 @@ struct BusState {
|
||||
bool cursor = false;
|
||||
uint16_t refresh_address = 0;
|
||||
uint16_t row_address = 0;
|
||||
|
||||
// Not strictly part of the bus state; provided because the partition between 6845 and bus handler
|
||||
// doesn't quite hold up in some emulated systems where the two are integrated and share more state.
|
||||
int field_count = 0;
|
||||
};
|
||||
|
||||
class BusHandler {
|
||||
@ -94,7 +98,7 @@ template <class T, CursorType cursor_type> class CRTC6845 {
|
||||
}
|
||||
|
||||
void set_register(uint8_t value) {
|
||||
static uint8_t masks[] = {
|
||||
static constexpr uint8_t masks[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f,
|
||||
0xff, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff
|
||||
};
|
||||
@ -262,11 +266,15 @@ template <class T, CursorType cursor_type> class CRTC6845 {
|
||||
is_cursor_line_ |= bus_state_.row_address == (registers_[10] & 0x1f);
|
||||
|
||||
switch(cursor_type) {
|
||||
// MDA-style blinking; timings are a bit of a guess for now.
|
||||
// MDA-style blinking.
|
||||
// https://retrocomputing.stackexchange.com/questions/27803/what-are-the-blinking-rates-of-the-caret-and-of-blinking-text-on-pc-graphics-car
|
||||
// gives an 8/8 pattern for regular blinking though mode 11 is then just a guess.
|
||||
case CursorType::MDA:
|
||||
switch(registers_[10] >> 5) {
|
||||
case 0b11: is_cursor_line_ &= (field_count_ & 15) < 5; break;
|
||||
case 0b00: is_cursor_line_ &= bool(field_count_ & 16); break;
|
||||
case 0b11: is_cursor_line_ &= (bus_state_.field_count & 8) < 3; break;
|
||||
case 0b00: is_cursor_line_ &= bool(bus_state_.field_count & 8); break;
|
||||
case 0b01: is_cursor_line_ = false; break;
|
||||
case 0b10: is_cursor_line_ = true; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
@ -279,9 +287,7 @@ template <class T, CursorType cursor_type> class CRTC6845 {
|
||||
line_is_visible_ = true;
|
||||
line_address_ = uint16_t((registers_[12] << 8) | registers_[13]);
|
||||
bus_state_.refresh_address = line_address_;
|
||||
if constexpr (cursor_type != CursorType::None) {
|
||||
++field_count_;
|
||||
}
|
||||
++bus_state_.field_count;
|
||||
}
|
||||
|
||||
Personality personality_;
|
||||
@ -309,8 +315,6 @@ template <class T, CursorType cursor_type> class CRTC6845 {
|
||||
unsigned int character_is_visible_shifter_ = 0;
|
||||
|
||||
bool is_cursor_line_ = false;
|
||||
|
||||
int field_count_ = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -181,14 +181,6 @@ class FloppyController {
|
||||
pic_.apply_edge<6>(true);
|
||||
} break;
|
||||
|
||||
case Command::Seek:
|
||||
printf("FDC: Seek %d:%d to %d\n", decoder_.target().drive, decoder_.target().head, decoder_.seek_target());
|
||||
drives_[decoder_.target().drive].track = decoder_.seek_target();
|
||||
|
||||
drives_[decoder_.target().drive].raised_interrupt = true;
|
||||
drives_[decoder_.target().drive].status = decoder_.drive_head() | uint8_t(Intel::i8272::Status0::SeekEnded);
|
||||
pic_.apply_edge<6>(true);
|
||||
break;
|
||||
case Command::Recalibrate:
|
||||
printf("FDC: Recalibrate\n");
|
||||
drives_[decoder_.target().drive].track = 0;
|
||||
@ -197,6 +189,14 @@ class FloppyController {
|
||||
drives_[decoder_.target().drive].status = decoder_.target().drive | uint8_t(Intel::i8272::Status0::SeekEnded);
|
||||
pic_.apply_edge<6>(true);
|
||||
break;
|
||||
case Command::Seek:
|
||||
printf("FDC: Seek %d:%d to %d\n", decoder_.target().drive, decoder_.target().head, decoder_.seek_target());
|
||||
drives_[decoder_.target().drive].track = decoder_.seek_target();
|
||||
|
||||
drives_[decoder_.target().drive].raised_interrupt = true;
|
||||
drives_[decoder_.target().drive].status = decoder_.drive_head() | uint8_t(Intel::i8272::Status0::SeekEnded);
|
||||
pic_.apply_edge<6>(true);
|
||||
break;
|
||||
|
||||
case Command::SenseInterruptStatus: {
|
||||
printf("FDC: SenseInterruptStatus\n");
|
||||
@ -215,7 +215,7 @@ class FloppyController {
|
||||
any_remaining_interrupts |= drives_[c].raised_interrupt;
|
||||
}
|
||||
if(!any_remaining_interrupts) {
|
||||
pic_.apply_edge<6>(any_remaining_interrupts);
|
||||
pic_.apply_edge<6>(false);
|
||||
}
|
||||
} break;
|
||||
case Command::Specify:
|
||||
@ -478,7 +478,7 @@ class MDA {
|
||||
template <int address>
|
||||
void write(uint8_t value) {
|
||||
if constexpr (address & 0x8) {
|
||||
printf("TODO: write MDA control %02x\n", value);
|
||||
outputter_.set_control(value);
|
||||
} else {
|
||||
if constexpr (address & 0x1) {
|
||||
crtc_.set_register(value);
|
||||
@ -491,8 +491,7 @@ class MDA {
|
||||
template <int address>
|
||||
uint8_t read() {
|
||||
if constexpr (address & 0x8) {
|
||||
printf("TODO: read MDA control\n");
|
||||
return 0xff;
|
||||
return outputter_.control();
|
||||
} else {
|
||||
return crtc_.get_register();
|
||||
}
|
||||
@ -505,7 +504,7 @@ class MDA {
|
||||
}
|
||||
|
||||
Outputs::Display::ScanStatus get_scaled_scan_status() const {
|
||||
return outputter_.crt.get_scaled_scan_status() / 4.0f;
|
||||
return outputter_.crt.get_scaled_scan_status() * 9.0f / 14.0f;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -519,11 +518,22 @@ class MDA {
|
||||
crt.set_display_type(Outputs::Display::DisplayType::RGB);
|
||||
}
|
||||
|
||||
void set_control(uint8_t control) {
|
||||
// b0: 'high resolution' (probably breaks if not 1)
|
||||
// b3: video enable
|
||||
// b5: enable blink
|
||||
control_ = control;
|
||||
}
|
||||
|
||||
uint8_t control() {
|
||||
return control_;
|
||||
}
|
||||
|
||||
void perform_bus_cycle_phase1(const Motorola::CRTC::BusState &state) {
|
||||
// Determine new output state.
|
||||
const OutputState new_state =
|
||||
(state.hsync | state.vsync) ? OutputState::Sync :
|
||||
(state.display_enable ? OutputState::Pixels : OutputState::Border);
|
||||
((state.display_enable && control_&0x08) ? OutputState::Pixels : OutputState::Border);
|
||||
|
||||
// Upon either a state change or just having accumulated too much local time...
|
||||
if(new_state != output_state || count > 882) {
|
||||
@ -585,6 +595,12 @@ class MDA {
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply blink if enabled.
|
||||
if((control_ & 0x20) && (attributes & 0x80) && (state.field_count & 16)) {
|
||||
row ^= 0xff;
|
||||
blank = (blank == off) ? intensity : off;
|
||||
}
|
||||
|
||||
if(((attributes & 7) == 1) && state.row_address == 13) {
|
||||
// Draw as underline.
|
||||
std::fill(pixel_pointer, pixel_pointer + 9, intensity);
|
||||
@ -631,6 +647,8 @@ class MDA {
|
||||
|
||||
const uint8_t *ram = nullptr;
|
||||
std::vector<uint8_t> font;
|
||||
|
||||
uint8_t control_ = 0;
|
||||
} outputter_;
|
||||
Motorola::CRTC::CRTC6845<CRTCOutputter, Motorola::CRTC::CursorType::MDA> crtc_;
|
||||
|
||||
@ -942,6 +960,8 @@ class IO {
|
||||
case 0x03f4: return fdc_.status();
|
||||
case 0x03f5: return fdc_.read();
|
||||
|
||||
case 0x03b8: return mda_.read<8>();
|
||||
|
||||
case 0x02e8: case 0x02e9: case 0x02ea: case 0x02eb:
|
||||
case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef:
|
||||
case 0x02f8: case 0x02f9: case 0x02fa: case 0x02fb:
|
||||
|
Loading…
Reference in New Issue
Block a user