mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-04-10 23:29:20 +00:00
Initial stab at keyboard beeper.
This commit is contained in:
@@ -122,6 +122,7 @@
|
||||
<Compile Include="Display\DisplayController.cs" />
|
||||
<Compile Include="Ethernet\HostEthernet.cs" />
|
||||
<Compile Include="Ethernet\IPacketInterface.cs" />
|
||||
<Compile Include="IOP\Tone.cs" />
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
|
||||
@@ -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<ushort> _outputPacket;
|
||||
|
||||
private List<ushort> _debugPacket = new List<ushort>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
//
|
||||
|
||||
@@ -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)
|
||||
|
||||
91
D/IOP/Tone.cs
Normal file
91
D/IOP/Tone.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the tone generator used to generate simple beeps.
|
||||
/// This is driven by an i8253 programmable interval timer.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user