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 virtualTranslationRegisterValue, ulong sp, ulong* regAXAddress, ulong* regBXAddress, ulong* regCXAddress)
58 {
59 Memory& mem = machine.GetMemory();
60 ulong prevRV = regs.GetSpecial(Registers.rV);
61 regs.SetSpecial(Registers.rV, virtualTranslationRegisterValue);
62 sp = sp + 8u;
63 mem.WriteULong(sp, regs.GetPC(), Protection.write);
64 sp = sp + 8u;
65 mem.WriteULong(sp, regs.GetSpecial(Registers.rA), Protection.write);
66 sp = sp + 8u;
67 mem.WriteULong(sp, regs.GetSpecial(Registers.rB), Protection.write);
68 sp = sp + 8u;
69 mem.WriteULong(sp, regs.GetSpecial(Registers.rD), Protection.write);
70 sp = sp + 8u;
71 mem.WriteULong(sp, regs.GetSpecial(Registers.rE), Protection.write);
72 sp = sp + 8u;
73 mem.WriteULong(sp, regs.GetSpecial(Registers.rH), Protection.write);
74 sp = sp + 8u;
75 mem.WriteULong(sp, regs.GetSpecial(Registers.rI), Protection.write);
76 sp = sp + 8u;
77 mem.WriteULong(sp, regs.GetSpecial(Registers.rJ), Protection.write);
78 sp = sp + 8u;
79 mem.WriteULong(sp, regs.GetSpecial(Registers.rM), Protection.write);
80 sp = sp + 8u;
81 mem.WriteULong(sp, regs.GetSpecial(Registers.rP), Protection.write);
82 sp = sp + 8u;
83 mem.WriteULong(sp, regs.GetSpecial(Registers.rR), Protection.write);
84 sp = sp + 8u;
85 mem.WriteULong(sp, regs.GetSpecial(Registers.rW), Protection.write);
86 sp = sp + 8u;
87 mem.WriteULong(sp, regs.GetSpecial(Registers.rX), Protection.write);
88 sp = sp + 8u;
89 mem.WriteULong(sp, regs.GetSpecial(Registers.rY), Protection.write);
90 sp = sp + 8u;
91 mem.WriteULong(sp, regs.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(sp, regs.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(sp, regs.Get(cast<byte>(i)), Protection.write);
124 sp = sp + 8u;
125 }
126 mem.WriteULong(sp, regs.GetSpecial(Registers.rL), Protection.write);
127 sp = sp + 8u;
128 mem.WriteULong(sp, regs.GetSpecial(Registers.rG), Protection.write);
129 sp = sp + 8u;
130 regs.SetSpecial(Registers.rV, prevRV);
131 return sp;
132 }
133 public nothrow ulong UnsaveContext(ulong virtualTranslationRegisterValue, ulong sp)
134 {
135 Memory& mem = machine.GetMemory();
136 regs.SetSpecial(Registers.rV, virtualTranslationRegisterValue);
137 sp = sp - 8u;
138 ulong rg = mem.ReadULong(sp, Protection.read);
139 regs.SetSpecial(Registers.rG, rg);
140 sp = sp - 8u;
141 ulong rl = mem.ReadULong(sp, Protection.read);
142 regs.SetSpecial(Registers.rL, rl);
143 for (int i = 255; i >= cast<int>(rg); --i;)
144 {
145 sp = sp - 8u;
146 regs.Set(cast<byte>(i), mem.ReadULong(sp, Protection.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(sp, Protection.read));
153 }
154 sp = sp - 8u;
155 regs.SetSpecial(Registers.rZ, mem.ReadULong(sp, Protection.read));
156 sp = sp - 8u;
157 regs.SetSpecial(Registers.rY, mem.ReadULong(sp, Protection.read));
158 sp = sp - 8u;
159 regs.SetSpecial(Registers.rX, mem.ReadULong(sp, Protection.read));
160 sp = sp - 8u;
161 regs.SetSpecial(Registers.rW, mem.ReadULong(sp, Protection.read));
162 sp = sp - 8u;
163 regs.SetSpecial(Registers.rR, mem.ReadULong(sp, Protection.read));
164 sp = sp - 8u;
165 regs.SetSpecial(Registers.rP, mem.ReadULong(sp, Protection.read));
166 sp = sp - 8u;
167 regs.SetSpecial(Registers.rM, mem.ReadULong(sp, Protection.read));
168 sp = sp - 8u;
169 regs.SetSpecial(Registers.rJ, mem.ReadULong(sp, Protection.read));
170 sp = sp - 8u;
171 regs.SetSpecial(Registers.rI, mem.ReadULong(sp, Protection.read));
172 sp = sp - 8u;
173 regs.SetSpecial(Registers.rH, mem.ReadULong(sp, Protection.read));
174 sp = sp - 8u;
175 regs.SetSpecial(Registers.rE, mem.ReadULong(sp, Protection.read));
176 sp = sp - 8u;
177 regs.SetSpecial(Registers.rD, mem.ReadULong(sp, Protection.read));
178 sp = sp - 8u;
179 regs.SetSpecial(Registers.rB, mem.ReadULong(sp, Protection.read));
180 sp = sp - 8u;
181 regs.SetSpecial(Registers.rA, mem.ReadULong(sp, Protection.read));
182 sp = sp - 8u;
183 regs.SetPC(mem.ReadULong(sp, Protection.read));
184 sp = sp - 8u;
185 regs.Set(regSP, sp);
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(pc, mem, x, y, z);
200 inst->Execute(regs, mem, x, y, z);
201 SetPC(inst, pc, prevPC);
202 IncrementCycleCounter();
203 CheckInterrupts(inst, x, y, z);
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(pc, mem, x, y, z);
219 while (inst != null)
220 {
221 if (pc == breakAddr && breakInst != 0u)
222 {
223 WriteInstruction(breakAddr, breakInst, mem);
224 breakAddr = 0u;
225 breakInst = 0u;
226 }
227 inst->Execute(regs, mem, x, y, z);
228 SetPC(inst, pc, prevPC);
229 IncrementCycleCounter();
230 inst = null;
231 CheckInterrupts(inst, x, y, z);
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.rV, MakeVirtualTranslationRegisterValue(kernelRootPageAddress, kernelAddressSpaceNumber));
247 ulong pte = mem.GetPageTableEntry(bootProcAddress);
248 if (pte != 0u)
249 {
250 ulong bootProcValue = mem.ReadULong(bootProcAddress, Protection.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& pc, Memory& mem, byte& x, byte& y, byte& z)
280 {
281 byte opCode = mem.ReadByte(pc, Protection.execute);
282 pc = pc + 1u;
283 x = mem.ReadByte(pc, Protection.execute);
284 pc = pc + 1u;
285 y = mem.ReadByte(pc, Protection.execute);
286 pc = pc + 1u;
287 z = mem.ReadByte(pc, Protection.execute);
288 pc = pc + 1u;
289 Instruction* inst = machine.GetInst(opCode);
290 return inst;
291 }
292 private nothrow void WriteInstruction(ulong addr, uint inst, Memory& mem)
293 {
294 mem.WriteUInt(addr, inst, Protection.execute);
295 }
296 private nothrow void IncrementCycleCounter()
297 {
298 ulong cycleCounter = regs.GetSpecial(Registers.rC);
299 ++cycleCounter;
300 regs.SetSpecial(Registers.rC, cycleCounter);
301 }
302 private nothrow void SetPC(Instruction* inst, ulong& newPC, ulong 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.rW, prevPC);
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 private nothrow void CheckInterrupts(Instruction*& inst, byte& x, byte& y, byte& z)
330 {
331 interruptOccurred = false;
332 regs.SetSpecial(Registers.rXX, 0u);
333 ulong bits = regs.GetInterruptBits();
334 if (bits != 0u)
335 {
336 uint low = cast<uint>(bits);
337 if (low != 0u)
338 {
339 CheckInterrupts(bits, irqFirstSetBegin, irqFirstSetEnd);
340 }
341 uint high = cast<uint>(bits >> 32u);
342 if (high != 0u)
343 {
344 CheckInterrupts(bits, irqSecondSetBegin, irqSecondSetEnd);
345 }
346 }
347 ulong rxx = regs.GetSpecial(Registers.rXX);
348 if (rxx != 0u)
349 {
350 MakeInstruction(cast<uint>(rxx), inst, x, y, z);
351 }
352 if (interruptOccurred)
353 {
354 startUserTimeFunction();
355 }
356 }
357 private inline nothrow void CheckInterrupts(ulong bits, int first, int 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 irq, ulong 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.rV, kernelRV);
379 }
380 ulong handlerAddress = machine.GetMemory().ReadULong(handlerPtrAddress, Protection.read);
381 regs.SetSpecial(Registers.rV, prevRV);
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(machine, irq);
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 inst, Instruction*& instruction, byte& x, byte& y, byte& 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 breakAddr, uint 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 }