1 using System;
  2 using System.Threading;
  3 
  4 namespace cmsx.machine
  5 {
  6     public const byte irqMax = 64u;
  7 
  8     public const byte irqSoftware = 0u;
  9     public const ulong SOFTWARE_INTERRUPT_BIT = cast<ulong>(1u) << irqSoftware;
 10     public const byte irqClock = 1u;
 11     public const ulong CLOCK_BIT = cast<ulong>(1u) << irqClock;
 12     public const byte irqDisk = 2u;
 13     public const ulong DISK_BIT = cast<ulong>(1u) << irqDisk;
 14     public const byte irqKeyboard = 3u;
 15     public const ulong KEYBOARD_BIT = cast<ulong>(1u) << irqKeyboard;
 16 
 17     public const int irqFirstSetBegin = 0;
 18     public const int irqFirstSetEnd = 4;
 19 
 20     public const byte irqR = 32u;
 21     public const ulong R_BIT = cast<ulong>(1u) << irqR;
 22     public const byte irqW = 33u;
 23     public const ulong W_BIT = cast<ulong>(1u) << irqW;
 24     public const byte irqX = 34u;
 25     public const ulong X_BIT = cast<ulong>(1u) << irqX;
 26     public const byte irqN = 35u;
 27     public const ulong N_BIT = cast<ulong>(1u) << irqN;
 28     public const byte irqK = 36u;
 29     public const ulong K_BIT = cast<ulong>(1u) << irqK;
 30     public const byte irqCOW = 37u;
 31     public const ulong COW_BIT = cast<ulong>(1u) << irqCOW;
 32     public const byte irqS = 38u;
 33     public const ulong S_BIT = cast<ulong>(1u) << irqS;
 34     public const byte irqP = 39u;
 35     public const ulong P_BIT = cast<ulong>(1u) << irqP;
 36 
 37     public const ulong MACHINE_INTERRUPT_BITS = R_BIT | W_BIT | X_BIT | N_BIT | K_BIT | COW_BIT | S_BIT | P_BIT;
 38 
 39     public const int irqSecondSetBegin = 32;
 40     public const int irqSecondSetEnd = 40;
 41 
 42     public const ulong ALL_INTERRUPT_BITS = 0xFFFFFFFFFFFFFFFFu;
 43 
 44     public delegate void InterruptHandler(Machine& machinebyte irq);
 45 
 46     public inline nothrow ulong MakeInterruptHandlerPtrAddress(byte irq)
 47     {
 48         return interruptVectorBaseAddress + cast<ulong>(8u) * irq;
 49     }
 50 
 51     public nothrow void SetProcessorToKernelMode(Registers& regs)
 52     {
 53         LockGuard<Mutex> lock(regs.GetInterruptMutex());
 54         regs.SetSpecial(Registers.rKregs.GetSpecial(Registers.rK) & ~N_BIT);
 55     }
 56 
 57     public nothrow void SetProcessorToUserMode(Registers& regs)
 58     {
 59         LockGuard<Mutex> lock(regs.GetInterruptMutex());
 60         regs.SetSpecial(Registers.rKregs.GetSpecial(Registers.rK) | MACHINE_INTERRUPT_BITS);
 61     }
 62 
 63     public nothrow bool IsProcessorInKernelMode(Registers& regs)
 64     {
 65         LockGuard<Mutex> lock(regs.GetInterruptMutex());
 66         return (regs.GetSpecial(Registers.rK) & N_BIT) == 0u;
 67     }
 68 
 69     public nothrow void DisableAllInterrupts(Registers& regs)
 70     {
 71         LockGuard<Mutex> lock(regs.GetInterruptMutex());
 72         regs.SetSpecial(Registers.rK0u);
 73     }
 74 
 75     public nothrow void EnableAllInterrupts(Registers& regs)
 76     {
 77         LockGuard<Mutex> lock(regs.GetInterruptMutex());
 78         regs.SetSpecial(Registers.rKALL_INTERRUPT_BITS);
 79     }
 80 
 81     public nothrow void SetSecurityViolation(Registers& regsulong virtualAddress)
 82     {
 83         LockGuard<Mutex> lock(regs.GetInterruptMutex());
 84         regs.SetSpecial(Registers.rZZvirtualAddress);
 85         regs.SetSpecial(Registers.rKregs.GetSpecial(Registers.rK) | S_BIT);
 86         regs.SetInterrupt(S_BIT);
 87     }
 88 
 89     private bool issuePageFault = true;
 90 
 91     public nothrow bool IssuePageFault()
 92     {
 93         return issuePageFault;
 94     }
 95 
 96     public nothrow void InvokePageFault(Registers& regsulong virtualAddressProtection pageProtectionProtection access)
 97     {
 98         if (!IssuePageFault())
 99         {
100             Console.Error() << regs.GetPC() << endl();
101             return;
102         }
103         regs.SetSpecial(Registers.rYYPackProtection(pageProtectionaccess));
104         regs.SetSpecial(Registers.rZZvirtualAddress);
105         LockGuard<Mutex> lock(regs.GetInterruptMutex());
106         ulong rq = regs.GetSpecial(Registers.rQ);
107         if (pageProtection == Protection.copyOnWrite)
108         {
109             rq = rq | COW_BIT;
110         }
111         else
112         {
113             if ((access & Protection.execute) != 0u)
114             {
115                 rq = rq | X_BIT;
116             }
117             else if ((access & Protection.write) != 0u)
118             {
119                 rq = rq | W_BIT;
120             }
121             else if ((access & Protection.read) != 0u)
122             {
123                 rq = rq | R_BIT;
124             }
125             else
126             {
127                 SetSecurityViolation(regsvirtualAddress);
128                 return;
129             }
130         }
131         regs.SetSpecial(Registers.rQrq);
132     }
133 
134     public nothrow string GetInterruptName(int irq)
135     {
136         switch (irq)
137         {
138             case irqSoftware: return "software";
139             case irqClock: return "clock";
140             case irqKeyboard: return "keyboard";
141             case irqR: return "read page fault";
142             case irqW: return "write page fault";
143             case irqX: return "execute page fault";
144             case irqCOW: return "copy-on-write page fault";
145             case irqN: return "kernel address page fault";
146             case irqK: return "kernel instruction";
147             case irqS: return "security violation";
148             case irqP: return "negative address";
149         }
150         return "unknown";
151     }
152 }