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 }