1 module dcpu16.emulator.devices.clock; 2 3 import dcpu16.emulator.idevice; 4 import dcpu16.emulator; 5 6 class Clock : IDevice 7 { 8 override uint id() const pure { return 0x12d0b402; }; 9 override uint manufacturer() const pure { return 0x1c6c8b36; }; 10 override ushort ver() const pure { return 2; }; 11 12 private Computer comp; 13 private ushort ticks; 14 private ushort timer; 15 private ushort timerInterval; // Means 60/n ticks per second 16 private ushort interruptMsg; 17 18 this(Computer c) 19 { 20 comp = c; 21 } 22 23 override void reset() 24 { 25 ticks = 0; 26 timer = 0; 27 timerInterval = 0; 28 interruptMsg = 0; 29 } 30 31 override void handleHardwareInterrupt(Computer _comp) 32 { 33 assert(comp == _comp); 34 35 with(InterruptActions) 36 with(comp) 37 with(cpu.regs) 38 switch(A) 39 { 40 case SET_SPEED: 41 timerInterval = B; 42 break; 43 44 case GET_TICKS: 45 c = ticks; 46 ticks = 0; 47 break; 48 49 case SET_INT: 50 interruptMsg = B; 51 break; 52 53 default: 54 break; 55 } 56 } 57 58 void clock60Hz() 59 { 60 if(timerInterval != 0) 61 { 62 timer++; 63 64 if(timer >= timerInterval) 65 { 66 timer = 0; 67 ticks++; 68 69 if(interruptMsg) 70 comp.cpu.addInterruptOrBurnOut(interruptMsg); 71 } 72 } 73 } 74 } 75 76 enum InterruptActions : ushort 77 { 78 SET_SPEED, 79 GET_TICKS, 80 SET_INT, 81 REAL_TIME = 0x10, 82 RUN_TIME, 83 SET_REAL_TIME, 84 RESET = 0xffff 85 } 86 87 unittest 88 { 89 enum str = import("tester_clock.bin"); 90 auto blob = cast(ubyte[]) str; 91 92 auto comp = new Computer(); 93 auto clock = new Clock(comp); 94 comp.devices ~= clock; 95 96 comp.load(blob, true); 97 98 size_t cnt; 99 ushort prev; 100 101 foreach(i; 0 .. 1_000_000) // 10 seconds on 1 kHz 102 { 103 comp.cpu.step(); 104 105 if(i % (100_000 / 60) == 0) 106 clock.clock60Hz(); 107 108 if(comp.cpu.regs.j != prev) 109 { 110 prev = comp.cpu.regs.j; 111 cnt++; 112 } 113 } 114 115 assert(cnt == 10); 116 }