further changes for v1.7: cpu fixes, support for 'hardware' devices, display to vnc
[dcpu16] / hw_clock.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4
5 #include "dcpu16.h"
6 #include "hw_clock.h"
7
8 static dcpu16_hw_signal_t clock_reset_;
9 static dcpu16_hw_signal_t clock_cycle_;
10 static dcpu16_hw_signal_t clock_hwi_;
11 static struct dcpu16_hw hw_ = {
12 .name_ = "Generic Clock (compatible)",
13 .id_l = 0xb402,
14 .id_h = 0x12d0,
15 .ver = 0x0001,
16 .mfg_l = 0x0000,
17 .mfg_h = 0x0000,
18 .hwi = clock_hwi_,
19 .cycle = clock_cycle_,
20 .reset = clock_reset_,
21 .data = (struct clock_ *)NULL
22 };
23
24 struct clock_ {
25 DCPU16_WORD cycle_;
26 DCPU16_WORD rate;
27 DCPU16_WORD tick;
28 DCPU16_WORD interrupt_message;
29 };
30
31 static
32 void clock_reset_(struct dcpu16 *vm, void *data) {
33 struct clock_ *clock = (struct clock_ *)data;
34
35 (void)vm;
36
37 memset(clock, 0, sizeof *clock);
38 }
39
40 static
41 void clock_cycle_(struct dcpu16 *vm, void *data) {
42 struct clock_ *clock = (struct clock_ *)data;
43
44 /* cycle is only called 100000 times per second */
45 /* maximum rate is 60hz / word_max = 3932160 */
46
47 if (clock->rate == 0)
48 return;
49
50 clock->cycle_++;
51 if (clock->cycle_ >= clock->rate) {
52 /* THIS CHECK IS WRONG, JUST A PLACEHOLDER */
53 clock->cycle_ = 0;
54 clock->tick += 1;
55
56 if (clock->interrupt_message) {
57 if (dcpu16_interrupt(vm, clock->interrupt_message))
58 vm->warn_cb_("%s: could not send interrupt", hw_.name_);
59 }
60 }
61 }
62
63 static
64 void clock_hwi_(struct dcpu16 *vm, void *data) {
65 struct clock_ *clock = (struct clock_ *)data;
66 DCPU16_WORD reg_a = vm->reg[DCPU16_REG_A];
67 DCPU16_WORD reg_b = vm->reg[DCPU16_REG_B];
68
69 switch (reg_a) {
70 case 0: /* set tick gather rate, 60hz/B */
71 clock->rate = reg_b;
72 break;
73
74 case 1: /* fetch elapsed count since rate was set */
75 vm->reg[DCPU16_REG_C] = clock->tick;
76 break;
77
78 case 2:
79 clock->interrupt_message = reg_b;
80 break;
81 }
82 }
83
84 /* instantitate a new clock */
85 struct dcpu16_hw *clock_new(struct dcpu16 *vm) {
86 struct dcpu16_hw *hw;
87
88 hw = calloc(1, sizeof *hw);
89 if (hw == NULL) {
90 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
91 return NULL;
92 }
93 memcpy(hw, &hw_, sizeof *hw);
94 hw->data = calloc(1, sizeof hw->data);
95 if (hw->data == NULL) {
96 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
97 free(hw);
98 return NULL;
99 }
100
101 return hw;
102 }
103
104 void clock_del(struct dcpu16_hw **hw) {
105 if (hw) {
106 free((*hw)->data);
107 (*hw)->data = NULL;
108
109 free((*hw));
110 *hw = NULL;
111 }
112 }