1
0
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:
Josh Dersch
2019-05-24 18:40:52 -07:00
parent 1c24c4642d
commit e1a2b549a0
9 changed files with 163 additions and 50 deletions

View File

@@ -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>

View File

@@ -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>();
}
}

View File

@@ -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.
}
}

View File

@@ -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;
//

View File

@@ -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
View 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;
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)