Skip to content

Commit

Permalink
Merge pull request #89 from dbalsom/ega_refactor
Browse files Browse the repository at this point in the history
Merge EGA work
  • Loading branch information
dbalsom authored Feb 19, 2024
2 parents 63278af + f789739 commit 60459b0
Show file tree
Hide file tree
Showing 52 changed files with 3,761 additions and 2,882 deletions.
4 changes: 2 additions & 2 deletions .idea/runConfigurations/Run_martypc__RELEASE___CGA_.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions .idea/runConfigurations/Run_martypc__RELEASE___EGA_.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 10 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,18 @@ advantage of this new system, and so now you can organize your media directories
* #### EGA Video Card
* EGA is back! A character-clocked EGA implementation is here, although it may still be a bit rough around the edges.
EGA will continue to be polished in upcoming releases.
* Features:
* Functional emulation of each of the 5 LSI chips on the EGA
* Per-scanline Pel panning
* Line compare register - See the status bar in Catacombs 3d!
* CGA compatibility mode - Play Alleycat!
* Software fonts - change your DOS font, or see a graphical mouse cursor in text mode (Norton Utilities 6.0)
* Known issues:
* No CGA emulation
* Not all registers properly emulated
* Pel panning implementation is a bit of a hack
* Some paging issues (flickering sprites in Dangerous Dave)
* Some scrolling issues (jerky motion in Commander Keen 4)
* Some more obscure registers not properly emulated / investigated (SOM, etc)
* Aperture defintions / adjustments not final
* Jerky scrolling in Commander Keen 1-3
* User-definable fonts not yet supported
* Implementation may be slow / unoptimized in parts

* #### MDA Video Card
* Not quite as a flashy as EGA, but the MDA card type is now also supported, and moreover, you can install an MDA
Expand Down
104 changes: 58 additions & 46 deletions core/src/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ pub struct BusInterface {
timing_table: Box<[TimingTableEntry; TIMING_TABLE_LEN]>,
machine_desc: Option<MachineDescriptor>,
keyboard_type: KeyboardType,
keyboard: Keyboard,
keyboard: Option<Keyboard>,
conventional_size: usize,
memory: Vec<u8>,
memory_mask: Vec<u8>,
Expand Down Expand Up @@ -444,7 +444,7 @@ impl Default for BusInterface {
timing_table: Box::new([TimingTableEntry { sys_ticks: 0, us: 0.0 }; TIMING_TABLE_LEN]),
machine_desc: None,
keyboard_type: KeyboardType::ModelF,
keyboard: Keyboard::new(KeyboardType::ModelF, false),
keyboard: None,
conventional_size: ADDRESS_SPACE,
memory: vec![OPEN_BUS_BYTE; ADDRESS_SPACE],
memory_mask: vec![0; ADDRESS_SPACE],
Expand Down Expand Up @@ -492,7 +492,6 @@ impl BusInterface {
timing_table,
machine_desc: Some(machine_desc),
keyboard_type,
keyboard: Keyboard::new(keyboard_type, false),
..BusInterface::default()
}
}
Expand Down Expand Up @@ -1423,7 +1422,7 @@ impl BusInterface {
// First we need to initialize the PPI. The PPI is used to read the system's DIP switches, so the PPI must be
// given several parameters from the machine configuration.

// Create vector of videotypes for PPI initialization.
// Create vector of video types for PPI initialization.
let video_types = machine_config
.video
.iter()
Expand Down Expand Up @@ -1503,6 +1502,19 @@ impl BusInterface {
.extend(port_list.into_iter().map(|p| (p, IoDeviceType::PicPrimary)));
self.pic1 = Some(pic1);

// Create keyboard if specified.
if let Some(kb_config) = &machine_config.keyboard {
let mut keyboard = Keyboard::new(kb_config.kb_type, false);

keyboard.set_typematic_params(
Some(kb_config.typematic),
kb_config.typematic_delay,
kb_config.typematic_rate,
);

self.keyboard = Some(keyboard);
}

// Create FDC if specified.
if let Some(fdc_config) = &machine_config.fdc {
let floppy_ct = fdc_config.drive.len();
Expand Down Expand Up @@ -1670,51 +1682,51 @@ impl BusInterface {
) -> Option<DeviceEvent> {
let mut event = None;

// Send keyboard events to devices.
if let Some(kb_event) = kb_event_opt {
//log::debug!("Got keyboard byte: {:02X}", kb_byte);
if let Some(keyboard) = &mut self.keyboard {
// Send keyboard events to devices.
if let Some(kb_event) = kb_event_opt {
//log::debug!("Got keyboard byte: {:02X}", kb_byte);

match kb_event.pressed {
true => self
.keyboard
.key_down(kb_event.keycode, &kb_event.modifiers, Some(kb_buf)),
false => self.keyboard.key_up(kb_event.keycode),
}
match kb_event.pressed {
true => keyboard.key_down(kb_event.keycode, &kb_event.modifiers, Some(kb_buf)),
false => keyboard.key_up(kb_event.keycode),
}

// Read a byte from the keyboard
if let Some(kb_byte) = self.keyboard.recv_scancode() {
// Do we have a PPI? if so, send the scancode to the PPI
if let Some(ppi) = &mut self.ppi {
ppi.send_keyboard(kb_byte);

if ppi.kb_enabled() {
if let Some(pic) = &mut self.pic1 {
// TODO: Should we let the PPI do this directly?
//log::warn!("sending kb interrupt for byte: {:02X}", kb_byte);
pic.pulse_interrupt(1);
// Read a byte from the keyboard
if let Some(kb_byte) = keyboard.recv_scancode() {
// Do we have a PPI? if so, send the scancode to the PPI
if let Some(ppi) = &mut self.ppi {
ppi.send_keyboard(kb_byte);

if ppi.kb_enabled() {
if let Some(pic) = &mut self.pic1 {
// TODO: Should we let the PPI do this directly?
//log::warn!("sending kb interrupt for byte: {:02X}", kb_byte);
pic.pulse_interrupt(1);
}
}
}
}
}
}

// Accumulate us and run the keyboard when scheduled.
self.kb_us_accum += us;
if self.kb_us_accum > KB_UPDATE_RATE {
self.keyboard.run(KB_UPDATE_RATE);
self.kb_us_accum -= KB_UPDATE_RATE;
// Accumulate us and run the keyboard when scheduled.
self.kb_us_accum += us;
if self.kb_us_accum > KB_UPDATE_RATE {
keyboard.run(KB_UPDATE_RATE);
self.kb_us_accum -= KB_UPDATE_RATE;

// Read a byte from the keyboard
if let Some(kb_byte) = self.keyboard.recv_scancode() {
// Do we have a PPI? if so, send the scancode to the PPI
if let Some(ppi) = &mut self.ppi {
ppi.send_keyboard(kb_byte);
// Read a byte from the keyboard
if let Some(kb_byte) = keyboard.recv_scancode() {
// Do we have a PPI? if so, send the scancode to the PPI
if let Some(ppi) = &mut self.ppi {
ppi.send_keyboard(kb_byte);

if ppi.kb_enabled() {
if let Some(pic) = &mut self.pic1 {
// TODO: Should we let the PPI do this directly?
//log::warn!("sending kb interrupt for byte: {:02X}", kb_byte);
pic.pulse_interrupt(1);
if ppi.kb_enabled() {
if let Some(pic) = &mut self.pic1 {
// TODO: Should we let the PPI do this directly?
//log::warn!("sending kb interrupt for byte: {:02X}", kb_byte);
pic.pulse_interrupt(1);
}
}
}
}
Expand Down Expand Up @@ -1870,13 +1882,13 @@ impl BusInterface {
for (_vid, video_dispatch) in self.videocards.iter_mut() {
match video_dispatch {
VideoCardDispatch::Mda(mda) => {
mda.run(DeviceRunTimeUnit::Microseconds(us));
mda.run(DeviceRunTimeUnit::Microseconds(us), &mut self.pic1);
}
VideoCardDispatch::Cga(cga) => {
self.cga_tick_accum += sys_ticks;

if self.cga_tick_accum > 8 {
cga.run(DeviceRunTimeUnit::SystemTicks(self.cga_tick_accum));
cga.run(DeviceRunTimeUnit::SystemTicks(self.cga_tick_accum), &mut self.pic1);
self.cga_tick_accum = 0;

if self.timer_trigger1_armed && pit_reload_value == 19912 {
Expand Down Expand Up @@ -1936,11 +1948,11 @@ impl BusInterface {
}
#[cfg(feature = "ega")]
VideoCardDispatch::Ega(ega) => {
ega.run(DeviceRunTimeUnit::Microseconds(us));
ega.run(DeviceRunTimeUnit::Microseconds(us), &mut self.pic1);
}
#[cfg(feature = "vga")]
VideoCardDispatch::Vga(vga) => {
vga.run(DeviceRunTimeUnit::Microseconds(us));
vga.run(DeviceRunTimeUnit::Microseconds(us), &mut self.pic1);
}
VideoCardDispatch::None => {}
}
Expand Down Expand Up @@ -2349,7 +2361,7 @@ impl BusInterface {
}
}

pub fn keyboard_mut(&mut self) -> &mut Keyboard {
&mut self.keyboard
pub fn keyboard_mut(&mut self) -> Option<&mut Keyboard> {
self.keyboard.as_mut()
}
}
4 changes: 2 additions & 2 deletions core/src/coreconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use crate::{
cpu_validator::ValidatorType,
device_traits::videocard::{ClockingMode, VideoType},
devices::keyboard::KeyboardType,
machine_types::{MachineType},
machine_types::MachineType,
};
use std::path::PathBuf;

Expand All @@ -59,7 +59,7 @@ pub trait CoreConfig {
fn get_machine_type(&self) -> MachineType;
fn get_machine_noroms(&self) -> bool;
fn get_machine_turbo(&self) -> bool;
fn get_keyboard_type(&self) -> Option<KeyboardType>;
//fn get_keyboard_type(&self) -> Option<KeyboardType>;
fn get_keyboard_layout(&self) -> Option<String>;
fn get_keyboard_debug(&self) -> bool;
//fn get_video_type(&self) -> Option<VideoType>;
Expand Down
5 changes: 3 additions & 2 deletions core/src/device_traits/videocard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ use crate::devices::ega::EGACard;
use crate::devices::vga::VGACard;
use crate::devices::{cga::CGACard, mda::MDACard};

use crate::devices::pic::Pic;
use serde::Deserialize;
use serde_derive::Serialize;

Expand Down Expand Up @@ -414,9 +415,9 @@ pub trait VideoCard {
fn get_videocard_string_state(&self) -> HashMap<String, Vec<(String, VideoCardStateEntry)>>;

/// Runs the video card device for the specified period of time
fn run(&mut self, time: DeviceRunTimeUnit);
fn run(&mut self, time: DeviceRunTimeUnit, pic: &mut Option<Pic>);

/// Runs the video card for a the specified number of video clocks
/// Runs the video card for the specified number of video clocks
/// Used for debugging by advancing the video card independent of machine state.
/// An implementor of VideoCard will have its own internal tick procedure.
fn debug_tick(&mut self, ticks: u32);
Expand Down
2 changes: 1 addition & 1 deletion core/src/devices/cga/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2227,7 +2227,7 @@ impl CGACard {
self.last_vsync_cycles = self.cycles;

if self.cycles_per_vsync > 300000 {
log::warn!(
log::trace!(
"do_vsync(): Excessively long frame. char_clock: {} cycles: {} beam_y: {}",
self.char_clock,
self.cycles_per_vsync,
Expand Down
4 changes: 2 additions & 2 deletions core/src/devices/cga/videocard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*/

use super::*;
use crate::device_traits::videocard::*;
use crate::{device_traits::videocard::*, devices::pic::Pic};

// Helper macro for pushing video card state entries.
// For CGA, we put the decorator first as there is only one register file an we use it to show the register index.
Expand Down Expand Up @@ -396,7 +396,7 @@ impl VideoCard for CGACard {
map
}

fn run(&mut self, time: DeviceRunTimeUnit) {
fn run(&mut self, time: DeviceRunTimeUnit, pic: &mut Option<Pic>) {
/*
if self.scanline > 1000 {
log::error!("run(): scanlines way too high: {}", self.scanline);
Expand Down
Loading

0 comments on commit 60459b0

Please sign in to comment.