/* signal attached hardware */
for (i = 0; i < vm->hw_table_entries_; i++) {
TRACE("%s>> notifying %s", __func__, vm->hw_table_[i].name_);
- vm->hw_table_[i].cycle(vm, vm->hw_table_[i].data);
+ vm->hw_table_[i].cycle(vm, &vm->hw_table_[i]);
}
}
}
dcpu16_cycle_inc(vm, 4);
if (vm->hw_table_[*a].hwi)
- vm->hw_table_[*a].hwi(vm, vm->hw_table_[*a].data);
+ vm->hw_table_[*a].hwi(vm, &vm->hw_table_[*a]);
else
WARN("hardware 0x%04x has no interrupt handler", *a);
}
printf("\n");
}
-/* dcpu16_hw_add
+/* instantiate a new 'hardware' device */
+struct dcpu16_hw *dcpu16_hw_new(struct dcpu16 *vm, struct dcpu16_hw_module *mod, void *data) {
+ struct dcpu16_hw *hw;
+
+ hw = calloc(1, sizeof *hw);
+ if (hw == NULL) {
+ vm->warn_cb_("%s():%s", "calloc", strerror(errno));
+ return NULL;
+ }
+ memcpy(hw, mod->template, sizeof *hw);
+ hw->vm = vm;
+ hw->mod = mod;
+
+ if (mod->data_init(hw, data)) {
+ vm->warn_cb_("failed to init hw module data");
+ free(hw);
+ return NULL;
+ }
+
+ return hw;
+}
+
+/* destroy a 'hardware' device */
+void dcpu16_hw_del(struct dcpu16_hw **hw) {
+ if (hw) {
+ if (*hw) {
+ if ((*hw)->mod->data_free) {
+ (*hw)->mod->data_free(*hw);
+ }
+ free(*hw);
+ *hw = NULL;
+ }
+ }
+}
+
+/* dcpu16_hw_ctl
+ * invokes per-module controls for hw device
+ */
+int dcpu16_hw_ctl(struct dcpu16_hw *hw, const char *cmd, void *data_in, void *data_out) {
+ if (hw) {
+ if (hw->mod) {
+ if (hw->mod->ctl) {
+ if (cmd) {
+ return hw->mod->ctl(hw, cmd, data_in, data_out);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* dcpu16_hw_attach
* registers new 'hardware' device with system
*/
-int dcpu16_hw_add(struct dcpu16 *vm, struct dcpu16_hw *hw) {
+int dcpu16_hw_attach(struct dcpu16 *vm, struct dcpu16_hw *hw) {
if (!vm || !hw)
return -1;
/* signal attached hardware */
for (i = 0; i < vm->hw_table_entries_; i++) {
if (vm->hw_table_[i].reset)
- vm->hw_table_[i].reset(vm, vm->hw_table_[i].data);
+ vm->hw_table_[i].reset(vm, &vm->hw_table_[i]);
}
memset(vm->reg, 0, sizeof vm->reg);