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