1 using System;
  2 using System.Threading;
  3 
  4 namespace cmsx.machine
  5 {
  6     public delegate void BootProc(Machine& machine);
  7     public const ulong bootProcAddress = kernelBaseAddress + dataSegmentBaseAddress;
  8 
  9     public delegate void InterruptReturnDelegate();
 10 
 11     public delegate void StartUserTimeFunction();
 12     public delegate void StopUserTimeFunction();
 13 
 14     private StartUserTimeFunction startUserTimeFunction;
 15     private StopUserTimeFunction stopUserTimeFunction;
 16 
 17     public nothrow void SetStartUserTimeFunction(StartUserTimeFunction fun)
 18     {
 19         startUserTimeFunction = fun;
 20     }
 21 
 22     public nothrow void SetStopUserTimeFunction(StopUserTimeFunction fun)
 23     {
 24         stopUserTimeFunction = fun;
 25     }
 26 
 27     public class Processor
 28     {
 29         public nothrow Processor(Machine& machine_) : machine(machine_)regs()exiting(false)
 30         {
 31         }
 32         public nothrow Registers& GetRegisters()
 33         {
 34             return regs;
 35         }
 36         public void Run()
 37         {
 38             Boot();
 39             if (Machine.GetFlag(Machine.Flags.debug))
 40             {
 41                 DoRunDebug();
 42             }
 43             else
 44             {
 45                 DoRun();
 46             }
 47             DoExit();
 48         }
 49         public void Exit()
 50         {
 51             exiting = true;
 52         }
 53         public nothrow void SetInterruptReturn(InterruptReturnDelegate interruptReturn_)
 54         {
 55             interruptReturn = interruptReturn_;
 56         }
 57         public nothrow ulong SaveContext(ulong virtualTranslationRegisterValueulong spulong* regAXAddressulong* regBXAddressulong* regCXAddress)
 58         {
 59             Memory& mem = machine.GetMemory();
 60             ulong prevRV = regs.GetSpecial(Registers.rV);
 61             regs.SetSpecial(Registers.rVvirtualTranslationRegisterValue);
 62             sp = sp + 8u;
 63             mem.WriteULong(spregs.GetPC()Protection.write);
 64             sp = sp + 8u;
 65             mem.WriteULong(spregs.GetSpecial(Registers.rA)Protection.write);
 66             sp = sp + 8u;
 67             mem.WriteULong(spregs.GetSpecial(Registers.rB)Protection.write);
 68             sp = sp + 8u;
 69             mem.WriteULong(spregs.GetSpecial(Registers.rD)Protection.write);
 70             sp = sp + 8u;
 71             mem.WriteULong(spregs.GetSpecial(Registers.rE)Protection.write);
 72             sp = sp + 8u;
 73             mem.WriteULong(spregs.GetSpecial(Registers.rH)Protection.write);
 74             sp = sp + 8u;
 75             mem.WriteULong(spregs.GetSpecial(Registers.rI)Protection.write);
 76             sp = sp + 8u;
 77             mem.WriteULong(spregs.GetSpecial(Registers.rJ)Protection.write);
 78             sp = sp + 8u;
 79             mem.WriteULong(spregs.GetSpecial(Registers.rM)Protection.write);
 80             sp = sp + 8u;
 81             mem.WriteULong(spregs.GetSpecial(Registers.rP)Protection.write);
 82             sp = sp + 8u;
 83             mem.WriteULong(spregs.GetSpecial(Registers.rR)Protection.write);
 84             sp = sp + 8u;
 85             mem.WriteULong(spregs.GetSpecial(Registers.rW)Protection.write);
 86             sp = sp + 8u;
 87             mem.WriteULong(spregs.GetSpecial(Registers.rX)Protection.write);
 88             sp = sp + 8u;
 89             mem.WriteULong(spregs.GetSpecial(Registers.rY)Protection.write);
 90             sp = sp + 8u;
 91             mem.WriteULong(spregs.GetSpecial(Registers.rZ)Protection.write);
 92             sp = sp + 8u;
 93             ulong rl = regs.GetSpecial(Registers.rL);
 94             #assert(rl < 256u);
 95             int n = cast<int>(rl);
 96             for (int i = 0u; i < n; ++i;)
 97             {
 98                 mem.WriteULong(spregs.Get(cast<byte>(i))Protection.write);
 99                 sp = sp + 8u;
100             }
101             ulong rg = regs.GetSpecial(Registers.rG);
102             #assert(rg < 256u);
103             for (int i = cast<int>(rg); i < 256; ++i;)
104             {
105                 switch (i)
106                 {
107                     case regAX:
108                     {
109                         if (regAXAddress != null) *regAXAddress = sp;
110                         break;
111                     }
112                     case regBX:
113                     {
114                         if (regBXAddress != null) *regBXAddress = sp;
115                         break;
116                     }
117                     case regCX:
118                     {
119                         if (regCXAddress != null) *regCXAddress = sp;
120                         break;
121                     }
122                 }
123                 mem.WriteULong(spregs.Get(cast<byte>(i))Protection.write);
124                 sp = sp + 8u;
125             }
126             mem.WriteULong(spregs.GetSpecial(Registers.rL)Protection.write);
127             sp = sp + 8u;
128             mem.WriteULong(spregs.GetSpecial(Registers.rG)Protection.write);
129             sp = sp + 8u;
130             regs.SetSpecial(Registers.rVprevRV);
131             return sp;
132         }
133         public nothrow ulong UnsaveContext(ulong virtualTranslationRegisterValueulong sp)
134         {
135             Memory& mem = machine.GetMemory();
136             regs.SetSpecial(Registers.rVvirtualTranslationRegisterValue);
137             sp = sp - 8u;
138             ulong rg = mem.ReadULong(spProtection.read);
139             regs.SetSpecial(Registers.rGrg);
140             sp = sp - 8u;
141             ulong rl = mem.ReadULong(spProtection.read);
142             regs.SetSpecial(Registers.rLrl);
143             for (int i = 255; i >= cast<int>(rg); --i;)
144             {
145                 sp = sp - 8u;
146                 regs.Set(cast<byte>(i)mem.ReadULong(spProtection.read));
147             }
148             int n = cast<int>(rl);
149             for (int i = n - 1; i >= 0; --i;)
150             {
151                 sp = sp - 8u;
152                 regs.Set(cast<byte>(i)mem.ReadULong(spProtection.read));
153             }
154             sp = sp - 8u;
155             regs.SetSpecial(Registers.rZmem.ReadULong(spProtection.read));
156             sp = sp - 8u;
157             regs.SetSpecial(Registers.rYmem.ReadULong(spProtection.read));
158             sp = sp - 8u;
159             regs.SetSpecial(Registers.rXmem.ReadULong(spProtection.read));
160             sp = sp - 8u;
161             regs.SetSpecial(Registers.rWmem.ReadULong(spProtection.read));
162             sp = sp - 8u;
163             regs.SetSpecial(Registers.rRmem.ReadULong(spProtection.read));
164             sp = sp - 8u;
165             regs.SetSpecial(Registers.rPmem.ReadULong(spProtection.read));
166             sp = sp - 8u;
167             regs.SetSpecial(Registers.rMmem.ReadULong(spProtection.read));
168             sp = sp - 8u;
169             regs.SetSpecial(Registers.rJmem.ReadULong(spProtection.read));
170             sp = sp - 8u;
171             regs.SetSpecial(Registers.rImem.ReadULong(spProtection.read));
172             sp = sp - 8u;
173             regs.SetSpecial(Registers.rHmem.ReadULong(spProtection.read));
174             sp = sp - 8u;
175             regs.SetSpecial(Registers.rEmem.ReadULong(spProtection.read));
176             sp = sp - 8u;
177             regs.SetSpecial(Registers.rDmem.ReadULong(spProtection.read));
178             sp = sp - 8u;
179             regs.SetSpecial(Registers.rBmem.ReadULong(spProtection.read));
180             sp = sp - 8u;
181             regs.SetSpecial(Registers.rAmem.ReadULong(spProtection.read));
182             sp = sp - 8u;
183             regs.SetPC(mem.ReadULong(spProtection.read));
184             sp = sp - 8u;
185             regs.Set(regSPsp);
186             return sp;
187         }
188         private void DoRun()
189         {
190             ClockDriver clockDriver(Clock.Instance());
191             Memory& mem = machine.GetMemory();
192             ulong pc = regs.GetPC();
193             while (pc != invalidAddress && !exiting)
194             {
195                 ulong prevPC = pc;
196                 byte x = 0u;
197                 byte y = 0u;
198                 byte z = 0u;
199                 Instruction* inst = FetchInstruction(pcmemxyz);
200                 inst->Execute(regsmemxyz);
201                 SetPC(instpcprevPC);
202                 IncrementCycleCounter();
203                 CheckInterrupts(instxyz);
204                 pc = regs.GetPC();
205             }
206         }
207         private void DoRunDebug()
208         {
209             ClockDriver clockDriver(Clock.Instance());
210             Memory& mem = machine.GetMemory();
211             ulong pc = regs.GetPC();
212             while (pc != invalidAddress && !exiting)
213             {
214                 ulong prevPC = pc;
215                 byte x = 0u;
216                 byte y = 0u;
217                 byte z = 0u;
218                 Instruction* inst = FetchInstruction(pcmemxyz);
219                 while (inst != null)
220                 {
221                     if (pc == breakAddr && breakInst != 0u)
222                     {
223                         WriteInstruction(breakAddrbreakInstmem);
224                         breakAddr = 0u;
225                         breakInst = 0u;
226                     }
227                     inst->Execute(regsmemxyz);
228                     SetPC(instpcprevPC);
229                     IncrementCycleCounter();
230                     inst = null;
231                     CheckInterrupts(instxyz);
232                     pc = regs.GetPC();
233                 }
234             }
235         }
236         private void Boot()
237         {
238             ulong kernelRootPageAddress = machine.GetKernelRootPageAddress();
239             Memory& mem = machine.GetMemory();
240             if (kernelRootPageAddress == 0u)
241             {
242                 kernelRootPageAddress = mem.AllocateRootPage();
243                 machine.SetKernelRootPageAddress(kernelRootPageAddress);
244             }
245             regs.SetPC(invalidAddress);
246             regs.SetSpecial(Registers.rVMakeVirtualTranslationRegisterValue(kernelRootPageAddresskernelAddressSpaceNumber));
247             ulong pte = mem.GetPageTableEntry(bootProcAddress);
248             if (pte != 0u)
249             {
250                 ulong bootProcValue = mem.ReadULong(bootProcAddressProtection.read);
251                 if (bootProcValue != 0u)
252                 {
253                     BootProc boot = cast<BootProc>(cast<void*>(bootProcValue));
254                     boot(machine);
255                 }
256                 else
257                 {
258                     if (!Machine.GetFlag(Machine.Flags.quiet))
259                     {
260                         Console.Error() << "machine boot procedure not set" << endl();
261                     }
262                 }
263             }
264             else
265             {
266                 if (!Machine.GetFlag(Machine.Flags.quiet))
267                 {
268                     Console.Error() << "machine boot procedure not set" << endl();
269                 }
270             }
271         }
272         private void DoExit()
273         {
274             if (Machine.GetFlag(Machine.Flags.verbose))
275             {
276                 Console.Out() << "machine exit." << endl();
277             }
278         }
279         private nothrow Instruction* FetchInstruction(ulong& pcMemory& membyte& xbyte& ybyte& z)
280         {
281             byte opCode = mem.ReadByte(pcProtection.execute);
282             pc = pc + 1u;
283             x = mem.ReadByte(pcProtection.execute);
284             pc = pc + 1u;
285             y = mem.ReadByte(pcProtection.execute);
286             pc = pc + 1u;
287             z = mem.ReadByte(pcProtection.execute);
288             pc = pc + 1u;
289             Instruction* inst = machine.GetInst(opCode);
290             return inst;
291         }
292         private nothrow void WriteInstruction(ulong addruint instMemory& mem)
293         {
294             mem.WriteUInt(addrinstProtection.execute);
295         }
296         private nothrow void IncrementCycleCounter()
297         {
298             ulong cycleCounter = regs.GetSpecial(Registers.rC);
299             ++cycleCounter;
300             regs.SetSpecial(Registers.rCcycleCounter);
301         }
302         private nothrow void SetPC(Instruction* instulong& newPCulong prevPC)
303         {
304             ulong pc = regs.GetPC();
305             if (!inst->IsJumpInst() && pc == prevPC)
306             {
307                 regs.SetPC(newPC);
308             }
309             else
310             {
311                 newPC = pc;
312             }
313             regs.SetSpecial(Registers.rWprevPC);
314         }
315 /*      previous interrupt checking code:
316 
317                 for (int irq = irqMax - 1; irq >= 0; --irq)
318                 {
319                     ulong irqBit = cast<ulong>(1) << cast<ulong>(irq);
320                     bool irqBitSet = (bits & irqBit) != 0u;
321                     if (irqBitSet)
322                     {
323                         ulong handlerPtrAddress = regs.GetSpecial(Registers.rTT) + 8u * cast<ulong>(irq);
324                         HandleInterrupt(cast<byte>(irq), handlerPtrAddress);
325                         regs.ResetInterrupt(irqBit);
326                     }
327                 }
328 */
329         private nothrow void CheckInterrupts(Instruction*& instbyte& xbyte& ybyte& z)
330         {
331             interruptOccurred = false;
332             regs.SetSpecial(Registers.rXX0u);
333             ulong bits = regs.GetInterruptBits();
334             if (bits != 0u)
335             {
336                 uint low = cast<uint>(bits);
337                 if (low != 0u)
338                 {
339                     CheckInterrupts(bitsirqFirstSetBeginirqFirstSetEnd);
340                 }
341                 uint high = cast<uint>(bits >> 32u);
342                 if (high != 0u)
343                 {
344                     CheckInterrupts(bitsirqSecondSetBeginirqSecondSetEnd);
345                 }
346             }
347             ulong rxx = regs.GetSpecial(Registers.rXX);
348             if (rxx != 0u)
349             {
350                 MakeInstruction(cast<uint>(rxx)instxyz);
351             }
352             if (interruptOccurred)
353             {
354                 startUserTimeFunction();
355             }
356         }
357         private inline nothrow void CheckInterrupts(ulong bitsint firstint last)
358         {
359             for (int irq = first; irq < last; ++irq;)
360             {
361                 ulong irqBit = cast<ulong>(1) << cast<ulong>(irq);
362                 bool irqBitSet = (bits & irqBit) != 0u;
363                 if (irqBitSet)
364                 {
365                     ulong handlerPtrAddress = regs.GetSpecial(Registers.rTT) + 8u * cast<ulong>(irq);
366                     HandleInterrupt(cast<byte>(irq)handlerPtrAddress);
367                 }
368             }
369         }
370         private void HandleInterrupt(byte irqulong handlerPtrAddress)
371         {
372             ulong prevRV = regs.GetSpecial(Registers.rV);
373             bool inKernelMode = IsProcessorInKernelMode(regs);
374             if (!inKernelMode)
375             {
376                 SetProcessorToKernelMode(regs);
377                 ulong kernelRV = MakeVirtualTranslationRegisterValue(machine.GetKernelRootPageAddress()kernelAddressSpaceNumber);
378                 regs.SetSpecial(Registers.rVkernelRV);
379             }
380             ulong handlerAddress = machine.GetMemory().ReadULong(handlerPtrAddressProtection.read);
381             regs.SetSpecial(Registers.rVprevRV);
382             if (handlerAddress != 0u)
383             {
384                 if (!interruptOccurred)
385                 {
386                     stopUserTimeFunction();
387                 }
388                 interruptOccurred = true;
389                 InterruptHandler handler = cast<InterruptHandler>(cast<void*>(handlerAddress));
390                 handler(machineirq);
391                 if (interruptReturn != InterruptReturnDelegate())
392                 {
393                     interruptReturn();
394                 }
395             }
396             else
397             {
398                 Panic("cannot handle " + GetInterruptName(irq) + " interrupt " + ToString(irq) + ", handler address is null");
399             }
400             if (!inKernelMode)
401             {
402                 SetProcessorToUserMode(regs);
403             }
404         }
405         private void MakeInstruction(uint instInstruction*& instructionbyte& xbyte& ybyte& z)
406         {
407             byte opCode = cast<byte>(inst >> 24u);
408             x = cast<byte>(inst >> 16u);
409             y = cast<byte>(inst >> 8u);
410             z = cast<byte>(inst);
411             instruction = machine.GetInst(opCode);
412         }
413         public void SetBreak(ulong breakAddruint breakInst)
414         {
415             this->breakAddr = breakAddr;
416             this->breakInst = breakInst;
417         }
418         public void ClearBreak()
419         {
420             this->breakAddr = 0u;
421             this->breakInst = 0u;
422         }
423         private Machine& machine;
424         private Registers regs;
425         private bool exiting;
426         private ulong breakAddr;
427         private uint breakInst;
428         private InterruptReturnDelegate interruptReturn;
429         private bool interruptOccurred;
430     }
431 }