further reorg of module abstraction and control interface
[dcpu16] / dcpu16.c
index ac052d59887a148f62f5195db9ac8c2c08557063..2b39bafd35507092237027462fdf3d1b419502f0 100644 (file)
--- a/dcpu16.c
+++ b/dcpu16.c
@@ -172,7 +172,7 @@ void dcpu16_cycle_inc(struct dcpu16 *vm, unsigned int n) {
         /* 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]);
         }
     }
 }
@@ -533,7 +533,7 @@ OP_IMPL(nbi_hwi) {
 
     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);
 }
@@ -1358,10 +1358,62 @@ void dcpu16_dump_ram(struct dcpu16 *vm, DCPU16_WORD start, DCPU16_WORD end) {
         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;
 
@@ -1450,7 +1502,7 @@ void dcpu16_reset(struct dcpu16 *vm) {
     /* 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);