initial api changes to support hw_ devices as more-generic attachable modules
[dcpu16] / hw_spc2000.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4
5 #include "dcpu16.h"
6 #include "hw_spc2000.h"
7
8 static dcpu16_hw_signal_t spc2000_reset_;
9 static dcpu16_hw_signal_t spc2000_cycle_;
10 static dcpu16_hw_signal_t spc2000_hwi_;
11 static struct dcpu16_hw hw_ = {
12 .vm = NULL,
13 .name_ = "SPC2000 - Suspension Chamber 2000",
14 .id_l = 0x1d9d,
15 .id_h = 0x40e4,
16 .ver = 0x005e,
17 .mfg_l = 0x8b36,
18 .mfg_h = 0x1c6c,
19 .hwi = spc2000_hwi_,
20 .cycle = spc2000_cycle_,
21 .reset = spc2000_reset_,
22 .data = (struct spc2000_ *)NULL
23 };
24
25 static dcpu16_hw_data_init_t spc2000_data_init_;
26 static dcpu16_hw_data_free_t spc2000_data_free_;
27 struct dcpu16_hw_module dcpu16_hw_module_spc2000 = {
28 .template = &hw_,
29 .data_init = spc2000_data_init_,
30 .data_free = spc2000_data_free_,
31 };
32
33 struct spc2000_ {
34 DCPU16_WORD skip_unit;
35 long long skip;
36 };
37
38 static
39 int spc2000_data_init_(struct dcpu16_hw *hw, void *extra) {
40 (void)extra;
41
42 hw->data = calloc(1, sizeof(struct spc2000_));
43 if (hw->data == NULL) {
44 hw->vm->warn_cb_("%s():%s", "calloc", strerror(errno));
45 return -1;
46 }
47 return 0;
48 }
49
50 static
51 void spc2000_data_free_(struct dcpu16_hw *hw) {
52 if (hw) {
53 if (hw->data) {
54 free(hw->data);
55 hw->data = NULL;
56 }
57 }
58 }
59
60 static
61 void spc2000_reset_(struct dcpu16 *vm, void *data) {
62 struct spc2000_ *spc2000 = (struct spc2000_ *)data;
63
64 (void)vm;
65
66 memset(spc2000, 0, sizeof *spc2000);
67 }
68
69 static
70 void spc2000_cycle_(struct dcpu16 *vm, void *data) {
71 struct spc2000_ *spc2000 = (struct spc2000_ *)data;
72
73 (void)vm;
74 (void)spc2000;
75 }
76
77 static
78 void spc2000_hwi_(struct dcpu16 *vm, void *data) {
79 struct spc2000_ *spc2000 = (struct spc2000_ *)data;
80 DCPU16_WORD reg_a = vm->reg[DCPU16_REG_A],
81 reg_b = vm->reg[DCPU16_REG_B];
82 long long x;
83
84 switch (reg_a) {
85 case 0: /* GET_STATUS */
86 case 2: /* TRIGGER_DEVICE */
87 /* check status */
88 vm->reg[DCPU16_REG_C] = 0;
89 vm->reg[DCPU16_REG_B] = 0;
90 if (reg_a == 0
91 || vm->reg[DCPU16_REG_C] != 0)
92 break;
93 /* trigger */
94 vm->warn_cb_("spc2000 triggered\n");
95 break;
96
97 case 1: /* SET_UNIT_TO_SKIP */
98 spc2000->skip = vm->ram[reg_b];
99 x = vm->ram[reg_b + 1];
100 spc2000->skip |= x << 16;
101 x = vm->ram[reg_b + 2];
102 spc2000->skip |= x << 32;
103 x = vm->ram[reg_b + 3];
104 spc2000->skip |= x << 48;
105 break;
106
107 case 3: /* SET_SKIP_UNIT */
108 spc2000->skip_unit = reg_b;
109 break;
110 }
111 }
112
113 struct dcpu16_hw *spc2000_new(struct dcpu16 *vm) {
114 struct dcpu16_hw *hw;
115
116 hw = calloc(1, sizeof *hw);
117 if (hw == NULL) {
118 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
119 return NULL;
120 }
121
122 memcpy(hw, &hw_, sizeof *hw);
123
124 hw->data = calloc(1, sizeof(struct spc2000_));
125 if (hw->data == NULL) {
126 vm->warn_cb_("%s():%s", "calloc", strerror(errno));
127 free(hw);
128 return NULL;
129 }
130
131 hw->vm = vm;
132
133 return hw;
134 }
135
136 void spc2000_del(struct dcpu16_hw **hw) {
137 if (hw) {
138 if (*hw) {
139 if ((*hw)->data) {
140 free((*hw)->data);
141 (*hw)->data = NULL;
142 }
143 free(*hw);
144 *hw = NULL;
145 }
146 }
147 }