diff --git a/D/Darkstar.csproj b/D/Darkstar.csproj
index f32bba3..4289c25 100644
--- a/D/Darkstar.csproj
+++ b/D/Darkstar.csproj
@@ -122,6 +122,7 @@
+
True
True
diff --git a/D/Ethernet/EthernetController.cs b/D/Ethernet/EthernetController.cs
index ebad542..52a674f 100644
--- a/D/Ethernet/EthernetController.cs
+++ b/D/Ethernet/EthernetController.cs
@@ -126,7 +126,7 @@ namespace D.Ethernet
public int EtherDisp()
{
//
- // Pin 139(YIODisp.1) : Hooked to "Attn," which appear to be whether any attention is needed by the receiver
+ // Pin 139(YIODisp.1) : Hooked to "Attn," which indicates whether any attention is needed by the receiver
// or transmitter.
// Pin 39(YIODisp.0) : "(schematic) Must be zero for the transmitting inner loop uCode. It is also used to
// determine if the Option card is plugged in."
@@ -343,8 +343,8 @@ namespace D.Ethernet
//
if (_fifo.Count > 0)
{
- //ss
- // if cycle == 2 we dequeue the next item from the FIFO;
+ //
+ // If cycle == 2 we dequeue the next item from the FIFO;
// otherwise the last-dequeued item is returned.
// (See OPT schematic, sheet 6:
// "<-EIData not in Cycle2 is rereading EIData in the case
@@ -359,8 +359,6 @@ namespace D.Ethernet
if (Log.Enabled) Log.Write(LogComponent.EthernetReceive, " <-EIData: Returning FIFO word 0x{0:x4}. FIFO count is now {1}",
value, _fifo.Count);
-
- _debugPacket.Add(value);
}
else
{
@@ -389,41 +387,6 @@ namespace D.Ethernet
_rxEvenLen = _loopBack || _localLoop ? true : _evenPacketLength;
if (Log.Enabled) Log.Write(LogComponent.EthernetReceive, " <-EIData: completing transfer.");
-
- if (Log.Enabled)
- {
- StringBuilder sb = new StringBuilder();
- int byteNum = 0;
- StringBuilder dataLine = new StringBuilder();
- StringBuilder asciiLine = new StringBuilder();
- dataLine.AppendFormat("000: ");
-
- for (int i = 0; i < _debugPacket.Count; i++)
- {
- dataLine.AppendFormat("{0:x2} {1:x2}", (_debugPacket[i] >> 8), _debugPacket[i] & 0xff);
- asciiLine.Append(GetPrintableChar((byte)(_debugPacket[i] >> 8)));
- asciiLine.Append(GetPrintableChar((byte)_debugPacket[i]));
-
- byteNum++;
- if ((byteNum % 16) == 0)
- {
- Log.Write(LogComponent.EthernetPacket, "{0} {1}", dataLine.ToString(), asciiLine.ToString());
- dataLine.Clear();
- asciiLine.Clear();
- dataLine.AppendFormat("{0:x3}: ", i + 1);
- byteNum = 0;
- }
- }
-
- if (byteNum > 0)
- {
- Log.Write(LogComponent.EthernetPacket, "{0} {1}", dataLine.ToString(), asciiLine.ToString());
- }
-
- Log.Write(LogComponent.EthernetPacket, "");
- }
-
- _debugPacket.Clear();
}
UpdateWakeup();
@@ -1019,7 +982,5 @@ namespace D.Ethernet
//
private IPacketInterface _hostInterface;
private Queue _outputPacket;
-
- private List _debugPacket = new List();
}
}
diff --git a/D/IO/FloppyDrive.cs b/D/IO/FloppyDrive.cs
index 9893ecb..c4e88d3 100644
--- a/D/IO/FloppyDrive.cs
+++ b/D/IO/FloppyDrive.cs
@@ -155,7 +155,7 @@ namespace D
if (DriveSelect && IsLoaded && !_index)
{
// Raise the index signal, hold for a short period.
- _index = true;
+ _index = true;
_system.Scheduler.Schedule(_indexDuration, IndexCallback);
if (Log.Enabled) Log.Write(LogComponent.IOPFloppy, "Disk rotation complete, raising INDEX signal for 10us.");
@@ -179,7 +179,7 @@ namespace D
// Index signal and timing
private bool _index;
- private ulong _indexInterval = 250 * Conversion.MsecToNsec; // 1/5 second at 300rpm
+ private ulong _indexInterval = 250 * Conversion.MsecToNsec; // 1/5 second at 300rpm - we slow this down just a bit.
private ulong _indexDuration = 10 * Conversion.UsecToNsec; // 10uSec duration for index signal.
}
}
diff --git a/D/IOP/IOProcessor.cs b/D/IOP/IOProcessor.cs
index 8a2f940..64314ff 100644
--- a/D/IOP/IOProcessor.cs
+++ b/D/IOP/IOProcessor.cs
@@ -54,6 +54,7 @@ namespace D.IOP
_floppyController = new FloppyController(_floppyDrive, _system);
_dma = new DMAController(this);
_tty = new Printer();
+ _tone = new Tone();
//
// Register DMA devices with controller
@@ -65,7 +66,7 @@ namespace D.IOP
_io.RegisterDevice(_floppyController);
_io.RegisterDevice(_dma);
_io.RegisterDevice(_system.CP);
- //_io.RegisterDevice(_tty);
+ _io.RegisterDevice(_tty);
Reset();
}
@@ -142,6 +143,11 @@ namespace D.IOP
get { return _tty; }
}
+ public Tone Tone
+ {
+ get { return _tone; }
+ }
+
private i8085 _cpu;
private IOPIOBus _io;
private I8085MemoryBus _mem;
@@ -155,6 +161,7 @@ namespace D.IOP
private Keyboard _keyboard;
private Mouse _mouse;
private Printer _tty;
+ private Tone _tone;
private DSystem _system;
//
diff --git a/D/IOP/MiscIO.cs b/D/IOP/MiscIO.cs
index 0a54104..dd6c275 100644
--- a/D/IOP/MiscIO.cs
+++ b/D/IOP/MiscIO.cs
@@ -116,6 +116,24 @@ namespace D.IOP
{
switch (port)
{
+ case 0x8d:
+ // i8253 Timer channel #1 - used to set the Keyboard bell (tone) frequency.
+ // This is a 16-bit value loaded one byte at a time, LSB first.
+ // Send the word off to the tone generator.
+ _iop.Tone.LoadInterval(value);
+ break;
+
+ case 0x8f:
+ // i8253 Timer Mode.
+ // This is used to control the timer used for the Keyboard bell
+ // and for the USART. It specifies which timer will be active,
+ // how that timer's interval is loaded, and what the output waveform
+ // looks like.
+ // At this time there's no particular reason to pay attention to what
+ // gets written here, as we don't actually emulate the i8253.
+ if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO port Timer Mode written {0:x2}", value);
+ break;
+
case 0xd0:
//
// DMA Test Register
@@ -160,6 +178,15 @@ namespace D.IOP
if (Log.Enabled) Log.Write(LogComponent.IOPMisc, "Misc IO Keyboard data clock.");
}
+ if ((value & 0x20) != 0)
+ {
+ _iop.Tone.EnableTone();
+ }
+ else
+ {
+ _iop.Tone.DisableTone();
+ }
+
if ((value & 0x10) != 0)
{
_iop.Keyboard.EnableDiagnosticMode();
@@ -401,6 +428,8 @@ namespace D.IOP
private readonly int[] _writePorts = new int[]
{
+ 0x8d, // i8253 Timer Control 1 (Tone frequency)
+ 0x8f, // i8253 Timer Mode
0xd0, // DMA Test Register
0xe9, // KB, MP, TOD clocks (write)
0xea, // Clear TOD interrupt (write)
diff --git a/D/IOP/Tone.cs b/D/IOP/Tone.cs
new file mode 100644
index 0000000..4e1fdd0
--- /dev/null
+++ b/D/IOP/Tone.cs
@@ -0,0 +1,91 @@
+using D.Logging;
+using SDL2;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace D.IOP
+{
+ ///
+ /// Implements the tone generator used to generate simple beeps.
+ /// This is driven by an i8253 programmable interval timer.
+ ///
+ public class Tone
+ {
+ public Tone()
+ {
+ Reset();
+ }
+
+ public void Reset()
+ {
+ _lsb = 0;
+ _loadLSB = true;
+ _frequency = 0.0;
+ _enabled = false;
+ _sampleOn = false;
+ _periodInSamples = 0;
+ }
+
+ public void LoadInterval(byte value)
+ {
+ if (_loadLSB)
+ {
+ _lsb = value;
+ }
+ else
+ {
+ //;Frequency constant (1843.2/f, f in kHz)
+ _frequency = ((value << 8) | value) / 1.8432;
+ if (Log.Enabled) Log.Write(LogComponent.Tone, "Tone frequency set to {0}", _frequency);
+ _periodInSamples = (44100.0 / _frequency) / 2;
+ }
+
+ _loadLSB = false;
+ }
+
+ public void EnableTone()
+ {
+ if (Log.Enabled) Log.Write(LogComponent.Tone, "Tone enabled.", _frequency);
+ _enabled = true;
+ }
+
+ public void DisableTone()
+ {
+ // if (Log.Enabled) Log.Write(LogComponent.Tone, "Tone disabled.", _frequency);
+ _enabled = false;
+ }
+
+ public void AudioCallback(IntPtr userData, IntPtr stream, int length)
+ {
+ byte[] samples = new byte[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ _position++;
+
+ if (_position > _periodInSamples)
+ {
+ _position -= _periodInSamples;
+ _sampleOn = !_sampleOn;
+ }
+
+ samples[i] = (byte)(_enabled ? (_sampleOn ? 0xff : 0x00) : 0x00);
+ }
+
+ // Marshal.Copy(samples, 0, stream, length);
+ }
+
+ private bool _loadLSB;
+ private byte _lsb;
+
+ private double _frequency;
+ private bool _enabled;
+ private double _position;
+ private double _periodInSamples;
+ private bool _sampleOn;
+ }
+}
diff --git a/D/Logging/Log.cs b/D/Logging/Log.cs
index 7608f0b..fc85083 100644
--- a/D/Logging/Log.cs
+++ b/D/Logging/Log.cs
@@ -81,6 +81,9 @@ namespace D.Logging
EthernetReceive = 0x8000000,
EthernetPacket = 0x10000000,
+ // Keyboard tone
+ Tone = 0x20000000,
+
// Configuration
Configuration = 0x40000000,
@@ -108,9 +111,9 @@ namespace D.Logging
{
static Log()
{
- Enabled = false;
- _components = LogComponent.None;
- _type = LogType.None;
+ Enabled = true;
+ _components = LogComponent.Tone | LogComponent.IOPPrinter;
+ _type = LogType.All;
_logIndex = 0;
}
diff --git a/D/Program.cs b/D/Program.cs
index 241b3e1..ed5e0c3 100644
--- a/D/Program.cs
+++ b/D/Program.cs
@@ -88,7 +88,7 @@ namespace D
// Cons up a system to run stuff on.
DSystem system = new DSystem();
- system.Reset();
+ system.Reset();
//
// Start the UI, this will not return from ShowDialog
diff --git a/D/UI/DWindow-IO.cs b/D/UI/DWindow-IO.cs
index c7f2aaf..09fdffe 100644
--- a/D/UI/DWindow-IO.cs
+++ b/D/UI/DWindow-IO.cs
@@ -28,6 +28,7 @@
using D.IOP;
+using D.Logging;
using SDL2;
using System;
using System.Collections.Generic;
@@ -974,7 +975,7 @@ namespace D.UI
int retVal;
// Get SDL humming
- if ((retVal = SDL.SDL_Init(SDL.SDL_INIT_VIDEO)) < 0)
+ if ((retVal = SDL.SDL_Init(SDL.SDL_INIT_EVERYTHING)) < 0)
{
throw new InvalidOperationException(String.Format("SDL_Init failed. Error {0:x}", retVal));
}
@@ -1028,6 +1029,26 @@ namespace D.UI
_renderEventType = SDL.SDL_RegisterEvents(1);
_renderEvent = new SDL.SDL_Event();
_renderEvent.type = (SDL.SDL_EventType)_renderEventType;
+
+
+
+ SDL.SDL_AudioSpec desired = new SDL.SDL_AudioSpec();
+ SDL.SDL_AudioSpec obtained = new SDL.SDL_AudioSpec();
+
+ desired.freq = 44100;
+ desired.format = SDL.AUDIO_U8;
+ desired.channels = 1;
+ desired.callback = _system.IOP.Tone.AudioCallback;
+ desired.samples = 1;
+
+ uint deviceId = SDL.SDL_OpenAudioDevice(null, 0, ref desired, out obtained, 0);
+
+
+ SDL.SDL_PauseAudioDevice(deviceId, 0);
+
+ if (Log.Enabled) Log.Write(LogComponent.Tone, "SDL Audio initialized, device id {0}", deviceId);
+
+
}
private void CreateDisplayTexture(bool filter)