Cosmos/source/Cosmos.HAL/PIT.cs
2015-07-28 20:18:14 -04:00

210 lines
6.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Cosmos.HAL {
/// <summary>
/// Programmable Interval Timer
/// with 1,193181818... MHz
/// </summary>
public class PIT : Device {
public class PITTimer : IDisposable {
internal int NSRemaining;
public int NanosecondsTimeout;
public bool Recuring;
internal int ID = -1;
public int TimerID {
get {
return ID;
}
}
public delegate void dOnTrigger();
public dOnTrigger HandleTrigger;
public PITTimer(dOnTrigger HandleOnTrigger, int NanosecondsTimeout, bool Recuring) {
this.HandleTrigger = HandleOnTrigger;
this.NanosecondsTimeout = NanosecondsTimeout;
this.NSRemaining = this.NanosecondsTimeout;
this.Recuring = Recuring;
}
public PITTimer(dOnTrigger HandleOnTrigger, int NanosecondsTimeout, int NanosecondsLeft) {
this.HandleTrigger = HandleOnTrigger;
this.NanosecondsTimeout = NanosecondsTimeout;
this.NSRemaining = NanosecondsLeft;
this.Recuring = true;
}
~PITTimer() {
Dispose();
}
public void Dispose() {
if (ID != -1) {
//Global.PIT.UnregisterTimer(ID);
}
}
}
protected Core.IOGroup.PIT IO = Core.Global.BaseIOGroups.PIT;
private List<PITTimer> ActiveHandlers = new List<PITTimer>();
private ushort _T0Countdown = 65535;
private ushort _T2Countdown = 65535;
private int TimerCounter = 0;
private bool WaitSignaled = false;
public const uint PITFrequency = 1193180;
public const uint PITDelayNS = 838;
public bool T0RateGen = false;
public ushort T0Countdown {
get {
return _T0Countdown;
}
set {
_T0Countdown = value;
IO.Command.Byte = (byte)(T0RateGen ? 0x34 : 0x30);
IO.Data0.Byte = (byte)(value & 0xFF);
IO.Data0.Byte = (byte)(value >> 8);
}
}
public uint T0Frequency {
get {
return (PITFrequency / ((uint)_T0Countdown));
}
set {
if (value < 19 || value > 1193180) {
throw new ArgumentException("Frequency must be between 19 and 1193180!");
}
T0Countdown = (ushort)(PITFrequency / value);
}
}
public uint T0DelyNS {
get {
return (PITDelayNS * _T0Countdown);
}
set {
if (value > 54918330)
throw new ArgumentException("Delay must be no greater that 54918330");
T0Countdown = (ushort)(value / PITDelayNS);
}
}
public ushort T2Countdown {
get {
return _T2Countdown;
}
set {
_T2Countdown = value;
IO.Command.Byte = 0xB6;
IO.Data0.Byte = (byte)(value & 0xFF);
IO.Data0.Byte = (byte)(value >> 8);
}
}
public uint T2Frequency {
get {
return (PITFrequency / ((uint)_T2Countdown));
}
set {
if (value < 19 || value > 1193180) {
throw new ArgumentException("Frequency must be between 19 and 1193180!");
}
T2Countdown = (ushort)(PITFrequency / value);
}
}
public uint T2DelyNS {
get {
return (PITDelayNS * _T2Countdown);
}
set {
if (value > 54918330)
throw new ArgumentException("Delay must be no greater than 54918330");
T2Countdown = (ushort)(value / PITDelayNS);
}
}
//TODO: Why is sound in PIT? Is it a function of the PIT?
public void EnableSound() {
//IO.Port61.Byte = (byte)(IO.Port61.Byte | 0x03);
}
public void DisableSound() {
//IO.Port61.Byte = (byte)(IO.Port61.Byte | 0xFC);
}
public void PlaySound(int aFreq) {
EnableSound();
T2Frequency = (uint)aFreq;
}
public void MuteSound() {
DisableSound();
}
private void SignalWait() {
WaitSignaled = true;
}
public void Wait(uint TimeoutMS) {
WaitSignaled = false;
RegisterTimer(new PITTimer(SignalWait, (int)(TimeoutMS * 1000000), false));
while (!WaitSignaled) {
Core.Global.CPU.Halt();
}
}
public void WaitNS(int TimeoutNS) {
WaitSignaled = false;
RegisterTimer(new PITTimer(SignalWait, TimeoutNS, false));
while (!WaitSignaled) {
Core.Global.CPU.Halt();
}
}
public void HandleInterrupt() {
int T0Delay = (int)T0DelyNS;
PITTimer hndlr = null;
for (int i = ActiveHandlers.Count - 1; i >= 0; i--) {
hndlr = ActiveHandlers[i];
hndlr.NSRemaining -= T0Delay;
if (hndlr.NSRemaining < 1) {
if (hndlr.Recuring) {
hndlr.NSRemaining = hndlr.NanosecondsTimeout;
} else {
hndlr.ID = -1;
ActiveHandlers.RemoveAt(i);
}
hndlr.HandleTrigger();
}
}
}
public int RegisterTimer(PITTimer timer) {
if (timer.ID != -1)
throw new InvalidOperationException("Timer has already been registered!");
timer.ID = (TimerCounter++);
ActiveHandlers.Add(timer);
return timer.ID;
}
public void UnregisterTimer(int timerid) {
for (int i = 0; i < ActiveHandlers.Count; i++) {
if (ActiveHandlers[i].ID == timerid) {
ActiveHandlers[i].ID = -1;
ActiveHandlers.RemoveAt(i);
return;
}
}
}
}
}