///////////////////////////////////////////////////////////////////////////////
//
//  Microsoft Research Singularity
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  File: HalDevices.cs
//
//  Note: This file implements the contract specified in HalDevices.csi which are
//        static methods calling the proper platform specific class at runtime.
//
//        Many of these methods may be called from C++ or ASM code (PIC functions)
//        so they need to be static.
//

using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;

using Microsoft.Singularity;
using Microsoft.Singularity.Hal;
using Microsoft.Singularity.Io;

namespace Microsoft.Singularity.Hal
{
    // Factory class
    [CLSCompliant(false)]
    public sealed class HalDevicesFactory
    {
        public static object Initialize(Processor processor)
        {
            HalDevicesOmap3430 devices = new HalDevicesOmap3430();
            devices.Initialize(processor);
            return devices;
        }
    }

    [CLSCompliant(false)]
    public sealed class HalDevicesOmap3430 : HalDevices
    {
        private static Pic pic;
        private static TimerOmap3430 timer;
        private static HalClockNull clock;
        private static HalScreenNull halScreen;
        private static HalMemoryNull halMemory;

        [CLSCompliant(false)]
        public override void Initialize(Processor rootProcessor)
        {
            DebugStub.Print("HalDevices.Initialize() - ARM\n");

            // PIC
            PnpConfig picConfig
                = (PnpConfig)IoSystem.YieldResources("/arm/ti/3430/INTCPS",
                                                     typeof(Pic));
            pic = new Pic(picConfig);
            pic.Initialize();

            // Timer
            PnpConfig timerConfig
                = (PnpConfig)IoSystem.YieldResources("/arm/ti/3430/GPTIMER1",
                                                     typeof(TimerOmap3430));
            timer = new TimerOmap3430(timerConfig, pic);
            byte timerInterrupt = timer.Initialize();

            // Real-time clock
            clock = new HalClockNull();
            byte clockInterrupt = clock.Initialize();
            bool noisyTimer = false;

            CalibrateTimers.Run(clock, timer);

            SystemClock.Initialize(clock, TimeSpan.FromHours(8).Ticks);

            rootProcessor.AddPic(pic);

            rootProcessor.AddTimer(timerInterrupt, timer);
            rootProcessor.AddClock(clockInterrupt, clock);

            // ----------------------------------------------------------
            // Add Srat tables to the Processor
            halMemory = new HalMemoryNull();
            ProcessorNode.AddMemory(halMemory);

            timer.Start();

            halScreen = new HalScreenNull();
            Console.Screen = (HalScreen)halScreen;
        }

        public override void ReleaseResources()
        {
            clock.ReleaseResources();
            clock = null;

            timer.ReleaseResources();
            timer = null;

            pic.ReleaseResources();
            pic = null;
        }

        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override byte GetMaximumIrq()
        {
            return pic.MaximumIrq;
        }

        //
        // Adding and removing interrupts from the Pic.
        //
        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override void EnableIoInterrupt(byte irq)
        {
            pic.EnableIrq(irq);
        }

        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override void DisableIoInterrupt(byte irq)
        {
            pic.DisableIrq(irq);
        }

        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override bool InternalInterrupt(byte interrupt)
        {
            // Strictly there are no interrupts internal to
            // this Hal instance.  In practice, some hardware seems
            // intent on firing an interrupt even if it is masked.
            //
            // Return true if interrupt appears to be valid but
            // is masked, false otherwise.
            byte irq = pic.InterruptToIrq(interrupt);

#if DEBUG_SPURIOUS
            DebugStub.Break();
#endif

            if (pic.IrqMasked(irq) == true) {
                DebugStub.WriteLine("--- Acked spurious Irq={0:x2}", __arglist(irq));
                pic.AckIrq(irq);
                return true;
            }
            return false;
        }

        [NoHeapAllocation]
        public override int GetProcessorCount()
        {
            return 1;
        }

        public override void StartApProcessors(int cpus)
        {
        }

        [NoHeapAllocation]
        public override void ResetApProcessors()
        {
        }

        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override void FreezeProcessors()
        {
        }

        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override void SendFixedIPI(byte vector, int from, int to)
        {
        }

        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override void BroadcastFixedIPI(byte vector, bool includeSelf)
        {
        }

        [CLSCompliant(false)]
        [NoHeapAllocation]
        public override void ClearFixedIPI(int interrupt)
        {
        }

        public override byte TranslatePciInterrupt(byte currentInterruptLine,
                                                   byte pciInterruptPin,
                                                   PciPort pciPort)
        {
            //
            // On a non-ACPI PC, there's nothing to translate;
            // just return the current interrupt line.
            //
            return currentInterruptLine;
        }
    }
}

