Skip to content

Commit

Permalink
INT8 counter should count Interrupt activations and not PIT counter (…
Browse files Browse the repository at this point in the history
…which runs backward). Remove timer hack to call vga card.
  • Loading branch information
kevinferrare committed Jan 23, 2024
1 parent 894e673 commit 3ac9b46
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 79 deletions.
2 changes: 1 addition & 1 deletion src/Spice86.Core/Emulator/Devices/Timer/Counter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ private byte Policy3(ushort value) {
return Lsb(value);
}

private void UpdateDesiredFreqency(long desiredFrequency) {
public void UpdateDesiredFreqency(long desiredFrequency) {
Activator.Frequency = desiredFrequency;
if (_loggerService.IsEnabled(Serilog.Events.LogEventLevel.Verbose)) {
_loggerService.Verbose("Updating counter {Index} frequency to {DesiredFrequency}", Index, desiredFrequency);
Expand Down
16 changes: 2 additions & 14 deletions src/Spice86.Core/Emulator/Devices/Timer/Timer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,13 @@ public class Timer : DefaultIOPortHandler, ITimeMultiplier {
private readonly Counter[] _counters = new Counter[3];
private readonly DualPic _dualPic;

private readonly IVideoCard? _vgaCard;

// screen refresh
private readonly Counter _vgaScreenRefreshCounter;

public Timer(State state, ILoggerService loggerService, DualPic dualPic, IVideoCard? vgaCard, CounterConfigurator counterConfigurator, bool failOnUnhandledPort) : base(state, failOnUnhandledPort, loggerService) {
public Timer(State state, ILoggerService loggerService, DualPic dualPic,CounterConfigurator counterConfigurator, bool failOnUnhandledPort) : base(state, failOnUnhandledPort, loggerService) {
_dualPic = dualPic;
_vgaCard = vgaCard;
for (int i = 0; i < _counters.Length; i++) {
_counters[i] = new Counter(state,
_loggerService,
i, counterConfigurator.InstanciateCounterActivator(state));
}
// screen refresh is 60hz regardless of the configuration
_vgaScreenRefreshCounter = new Counter(state, _loggerService, 4, new TimeCounterActivator(1));
_vgaScreenRefreshCounter.SetValue((int)(Counter.HardwareFrequency / 60));
}

/// <inheritdoc cref="ITimeMultiplier" />
Expand Down Expand Up @@ -113,14 +104,11 @@ public override void WriteByte(int port, byte value) {
base.WriteByte(port, value);
}


public void Tick() {
if (_counters[0].ProcessActivation()) {
_dualPic.ProcessInterruptRequest(0);
}

if (_vgaScreenRefreshCounter.ProcessActivation()) {
_vgaCard?.UpdateScreen();
}
}

private static bool IsCounterRegisterPort(int port) => port is >= CounterRegisterZero and <= CounterRegisterTwo;
Expand Down
13 changes: 0 additions & 13 deletions src/Spice86.Core/Emulator/Devices/Video/IVideoCard.cs

This file was deleted.

43 changes: 24 additions & 19 deletions src/Spice86.Core/Emulator/Devices/Video/VgaCard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ namespace Spice86.Core.Emulator.Devices.Video;
using Spice86.Shared.Emulator.Video;
using Spice86.Shared.Interfaces;

using System.Diagnostics;

/// <summary>
/// Thin interface between renderer and gui.
/// </summary>
public class VgaCard : IVideoCard {
public class VgaCard : IDebuggableComponent {
private readonly IGui? _gui;
private readonly ILoggerService _logger;
private readonly IVgaRenderer _renderer;
private int _renderHeight;
private int _renderWidth;
private int _requiredBufferSize;

/// <summary>
/// Create a new VGA card.
Expand All @@ -24,30 +23,36 @@ public VgaCard(IGui? gui, IVgaRenderer renderer, ILoggerService loggerService) {
_gui = gui;
_logger = loggerService;
_renderer = renderer;
_renderWidth = renderer.Width;
_renderHeight = renderer.Height;
_requiredBufferSize = _renderWidth * _renderHeight;
if (gui is not null) {
gui.RenderScreen += (_, e) => Render(e);
if (_gui is not null) {
_gui.RenderScreen += (_, e) => Render(e);
// Init bitmaps, needed for GUI to start calling Render function
_gui.SetResolution(_renderer.Width, _renderer.Height);
}
}

public void UpdateScreen() {
if (_renderer.Width != _renderWidth || _renderer.Height != _renderHeight) {
_gui?.SetResolution(_renderer.Width, _renderer.Height);
_renderWidth = _renderer.Width;
_renderHeight = _renderer.Height;
_requiredBufferSize = _renderWidth * _renderHeight;
private bool EnsureGuiResolutionMatchesHardware() {
if (_renderer.Width == _gui?.Width && _renderer.Height == _gui?.Height) {
// Resolution is matching, nothing to do.
return true;
}
_gui?.UpdateScreen();
_gui?.SetResolution(_renderer.Width, _renderer.Height);
// Wait for it to be applied
while (_renderer.Width != _gui?.Width || _renderer.Height != _gui?.Height);
// Report that resolution did not match
return false;
}


/// <inheritdoc />
private unsafe void Render(UIRenderEventArgs uiRenderEventArgs) {
if (!EnsureGuiResolutionMatchesHardware()) {
// Gui resolution had to be changed, UI event is not valid anymore.
return;
}
var buffer = new Span<uint>((void*)uiRenderEventArgs.Address, uiRenderEventArgs.Length);
if (buffer.Length < _requiredBufferSize && _logger.IsEnabled(LogEventLevel.Warning)) {
int requiredBufferSize = _renderer.Width * _renderer.Height;
if (buffer.Length < requiredBufferSize && _logger.IsEnabled(LogEventLevel.Warning)) {
_logger.Warning("Buffer size {BufferLength} is too small for the required buffer size {RequiredBufferSize} for render resolution {RenderWidth} x {RenderHeight}",
buffer.Length, _requiredBufferSize, _renderWidth, _renderHeight);
buffer.Length, requiredBufferSize, _renderer.Width, _renderer.Height);
return;
}
_renderer.Render(buffer);
Expand Down
23 changes: 0 additions & 23 deletions src/Spice86.Core/Emulator/Gdb/GdbCustomCommandsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ private string ExecuteCustomCommand(ExecutionFlowRecorder executionFlowRecorder,
"dumpall" => DumpAll(executionFlowRecorder, functionHandler),
"breakcycles" => BreakCycles(args),
"breakcsip" => BreakCsIp(args),
"vbuffer" => Vbuffer(args),
_ => InvalidCommand(originalCommand),
};
}
Expand Down Expand Up @@ -257,11 +256,6 @@ private string Help(string additionnalMessage) {
- peekRet<optional type>: displays the return address of the current function as stored in the stack in RAM.If a parameter is provided, dump the return on the stack as if the return was one of the provided type. Valid values are: {GetValidRetValues()}
- state: displays the state of the machine
- ramx: displays the content of ram at the specified segmented address with x being the number of bits to extract. Example: ram8 DS:1234 => Will display the byte at address DS:1234
- vbuffer: family of commands to control video bufers:
- vbuffer refresh: refreshes the screen
- vbuffer add<address> <resolution> <scale?>: Example vbuffer add 0x1234 320x200 1.5 -> Add an additional buffer displaying what is at address 0x1234, with resolution 320x200 and scale 1.5
- vbuffer remove <address>: Deletes the buffer at address
- vbuffer list: Lists the buffers currently displayed
");
}

Expand Down Expand Up @@ -301,21 +295,4 @@ private string State() {
string state = _state.ToString();
return _gdbIo.GenerateMessageToDisplayResponse(state);
}

private string Vbuffer(string[] args) {
try {
string action = ExtractAction(args);

// Actions for 1 parameter
if ("refresh".Equals(action)) {
_gui?.UpdateScreen();
return _gdbIo.GenerateResponse("");
} else {
return _gdbIo.GenerateMessageToDisplayResponse($"Could not understand action {action}");
}
} catch (ArgumentException e) {
e.Demystify();
return _gdbIo.GenerateMessageToDisplayResponse(e.Message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ public TimerInt8Handler(IMemory memory, Cpu cpu, DualPic dualPic, Timer timer, B

/// <inheritdoc />
public override void Run() {
long numberOfTicks = _timer.NumberOfTicks;
TickCounterValue = (uint)numberOfTicks;
TickCounterValue++;
_dualPic.AcknowledgeInterrupt(0);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Spice86.Core/Emulator/VM/Machine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public sealed class Machine : IDisposable, IDebuggableComponent {
/// <summary>
/// The VGA Card.
/// </summary>
public IVideoCard VgaCard { get; }
public VgaCard VgaCard { get; }

/// <summary>
/// The VGA Registers
Expand Down Expand Up @@ -226,7 +226,7 @@ public Machine(IGui? gui, State cpuState, IOPortDispatcher ioPortDispatcher, ILo
VgaRenderer = new Renderer(VgaRegisters, vgaMemory);
VgaCard = new VgaCard(gui, VgaRenderer, loggerService);

Timer = new Timer(CpuState, loggerService, DualPic, VgaCard, counterConfigurator, configuration.FailOnUnhandledPort);
Timer = new Timer(CpuState, loggerService, DualPic, counterConfigurator, configuration.FailOnUnhandledPort);
if (gui is not null) {
gui.ProgrammableIntervalTimer = Timer;
}
Expand Down
7 changes: 3 additions & 4 deletions src/Spice86.Shared/Interfaces/IGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,9 @@ public interface IGui {
/// </summary>
double MouseY { get; set; }

/// <summary>
/// Refresh the display with the content of the video ram.
/// </summary>
void UpdateScreen();
public int Width { get; }

Check warning on line 46 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Missing XML comment for publicly visible type or member 'IGui.Width'

Check warning on line 46 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Missing XML comment for publicly visible type or member 'IGui.Width'

Check warning on line 46 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Missing XML comment for publicly visible type or member 'IGui.Width'

Check warning on line 46 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Missing XML comment for publicly visible type or member 'IGui.Width'

public int Height { get; }

Check warning on line 48 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Missing XML comment for publicly visible type or member 'IGui.Height'

Check warning on line 48 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Missing XML comment for publicly visible type or member 'IGui.Height'

Check warning on line 48 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Missing XML comment for publicly visible type or member 'IGui.Height'

Check warning on line 48 in src/Spice86.Shared/Interfaces/IGui.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Missing XML comment for publicly visible type or member 'IGui.Height'

/// <summary>
/// On video mode change: Set Resolution of the video source for the GUI to display
Expand Down
3 changes: 2 additions & 1 deletion src/Spice86/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ public void ShowColorPalette() {
[RelayCommand]
public void ResetTimeMultiplier() => TimeMultiplier = Configuration.TimeMultiplier;

public void UpdateScreen() {
private void InitializeRenderingThread() {
if (_disposed || _isSettingResolution || _isAppClosing || _uiUpdateMethod is null || Bitmap is null || RenderScreen is null) {
return;
}
Expand Down Expand Up @@ -453,6 +453,7 @@ public void SetResolution(int width, int height) => _uiDispatcher.Post(() => {
}
}
_isSettingResolution = false;
InitializeRenderingThread();
}, DispatcherPriority.MaxValue);

public event EventHandler<UIRenderEventArgs>? RenderScreen;
Expand Down

0 comments on commit 3ac9b46

Please sign in to comment.