cycles now correctly accounted for
authorJustin Wind <justin.wind@gmail.com>
Thu, 17 May 2012 21:11:41 +0000 (14:11 -0700)
committerJustin Wind <justin.wind@gmail.com>
Thu, 17 May 2012 21:11:41 +0000 (14:11 -0700)
Previously, hardware &c was only signaled for a cycle once per instruction step, rather than for the full count of cycles the instruction took.

dcpu16.c
dcpu16.h
hw_lem1802.c
vm-dcpu16.c

index 616237de3d99d7bc2628cd405ea6f8ee65c2fad1..ac052d59887a148f62f5195db9ac8c2c08557063 100644 (file)
--- a/dcpu16.c
+++ b/dcpu16.c
@@ -11,6 +11,7 @@
 
 /*
  *  emulates the DCPU16 system from http://0x10c.com/doc/dcpu-16.txt
+ *  currently emulates '1.7' spec from http://pastebin.com/Q4JvQvnM
  *  
  *  I couldn't remember ever implementing an emulator before, so this
  *  happened.  As such, consider this a toy in progress.
@@ -26,7 +27,6 @@
  *    !! v1.7 hardware interface needs to be finished
  *    !! v1.7 interrupts need to be finished
  *    change api to print into buffers rather than stdio
- *    refactor opcode functiontables into switch statements
  *    let callbacks determine whether to override events, or just observe
  *    sort init callbacks by base addr, to call in-order
  *    make all callbacks register addr range of interest
@@ -157,6 +157,26 @@ DCPU16_WORD interrupt_dequeue_(struct dcpu16 *vm) {
     return message;
 }
 
+inline
+void dcpu16_cycle_inc(struct dcpu16 *vm, unsigned int n) {
+    size_t i;
+
+    while (n--) {
+        /* new cycle */
+        vm->cycle_ += 1;
+        TRACE("%s>> starting cycle %llu", vm->cycle_);
+
+        /* signal interested cycle hooks */
+        acct_event_(vm, DCPU16_ACCT_EV_CYCLE, vm->reg[DCPU16_REG_PC]);
+
+        /* 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);
+        }
+    }
+}
+
 /*  value_decode_
  * sets *v to be the address of the represented value
  * value_is_a is 0 for b, 1 for a, alters behavior of some operands
@@ -336,7 +356,7 @@ struct opcode_entry {
                       &vm->reg_work_[1], &a, &ev_a_addr,\
                       &pc_adjust, &sp_adjust, &cycle_adjust);\
         vm->reg[DCPU16_REG_SP] += sp_adjust;\
-        vm->cycle += cycle_adjust;\
+        dcpu16_cycle_inc(vm, cycle_adjust);\
     } while (0)
 #define OP_NBI_ (void)val_b, (void)b, (void)ev_b_addr, (void)val_b_data
 #define OP_BASIC_ value_decode_(vm, val_b, 0, val_b_data,\
@@ -384,7 +404,7 @@ OP_IMPL(nbi_jsr) {
     vm->ram[ --vm->reg[DCPU16_REG_SP] ] = vm->reg[DCPU16_REG_PC];
     vm->reg[DCPU16_REG_PC] = *a;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(vm->reg[DCPU16_REG_SP] + 1);
 }
@@ -419,7 +439,7 @@ OP_IMPL(nbi_int) {
         vm->reg[0] = *a;
     }
 
-    vm->cycle += 4;
+    dcpu16_cycle_inc(vm, 4);
 }
 
 OP_IMPL(nbi_iag) {
@@ -427,6 +447,8 @@ OP_IMPL(nbi_iag) {
 
     *a = vm->reg[DCPU16_REG_IA];
 
+    dcpu16_cycle_inc(vm, 1);
+
     ACCT_W(ev_a_addr);
 }
 
@@ -435,6 +457,8 @@ OP_IMPL(nbi_ias) {
 
     vm->reg[DCPU16_REG_IA] = *a;
 
+    dcpu16_cycle_inc(vm, 1);
+
     ACCT_R(ev_a_addr);
 }
 
@@ -445,6 +469,8 @@ OP_IMPL(nbi_rfi) {
     vm->interrupts_deferred_ = 0;
     vm->reg[DCPU16_REG_A] = vm->ram[vm->reg[DCPU16_REG_SP]++];
     vm->reg[DCPU16_REG_PC] = vm->ram[vm->reg[DCPU16_REG_SP]++];
+
+    dcpu16_cycle_inc(vm, 3);
 }
 
 OP_IMPL(nbi_iaq) {
@@ -456,6 +482,8 @@ OP_IMPL(nbi_iaq) {
         vm->interrupts_deferred_ = 0;
     }
 
+    dcpu16_cycle_inc(vm, 2);
+
     ACCT_R(ev_a_addr);
 }
 
@@ -466,7 +494,7 @@ OP_IMPL(nbi_hwn) {
 
     *a = vm->hw_table_entries_;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(nbi_hwq) {
@@ -490,7 +518,7 @@ OP_IMPL(nbi_hwq) {
     vm->reg[DCPU16_REG_X] = vm->hw_table_[*a].mfg_l;
     vm->reg[DCPU16_REG_Y] = vm->hw_table_[*a].mfg_h;
 
-    vm->cycle += 4;
+    dcpu16_cycle_inc(vm, 4);
 }
 
 OP_IMPL(nbi_hwi) {
@@ -503,7 +531,7 @@ OP_IMPL(nbi_hwi) {
         return;
     }
 
-    vm->cycle += 4;
+    dcpu16_cycle_inc(vm, 4);
     if (vm->hw_table_[*a].hwi)
         vm->hw_table_[*a].hwi(vm, vm->hw_table_[*a].data);
     else
@@ -518,7 +546,7 @@ OP_IMPL(nbi_hcf) {
     vm->on_fire_ = 1;
     WARN("system on fire");
 
-    vm->cycle += 9;
+    dcpu16_cycle_inc(vm, 9);
 }
 
 static const struct opcode_entry opcode_nbi_entries[] = {
@@ -583,7 +611,7 @@ OP_IMPL(set) {
      */
     *b = *a;
 
-    vm->cycle += 1;
+    dcpu16_cycle_inc(vm, 1);
 
     ACCT_W(ev_b_addr);
 }
@@ -599,7 +627,7 @@ OP_IMPL(add) {
     *b = acc;
     vm->reg[DCPU16_REG_EX] = (acc > 0xffff);
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(ev_b_addr);
 }
@@ -615,7 +643,7 @@ OP_IMPL(sub) {
     *b = acc;
     vm->reg[DCPU16_REG_EX] = (acc > 0xffff);
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(ev_b_addr);
 }
@@ -631,7 +659,7 @@ OP_IMPL(mul) {
     *b = acc;
     vm->reg[DCPU16_REG_EX] = acc >> 16;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(ev_b_addr);
 }
@@ -647,7 +675,7 @@ OP_IMPL(mli) {
     *b = acc;
     vm->reg[DCPU16_REG_EX] = acc >> 16;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(ev_b_addr);
 }
@@ -667,7 +695,7 @@ OP_IMPL(div) {
         vm->reg[DCPU16_REG_EX] = (*b << 16) / *a;
     }
 
-    vm->cycle += 3;
+    dcpu16_cycle_inc(vm, 3);
 
     ACCT_W(ev_b_addr);
 }
@@ -687,7 +715,7 @@ OP_IMPL(dvi) {
         vm->reg[DCPU16_REG_EX] = (short)(*b << 16) / (short)*a;
     }
 
-    vm->cycle += 3;
+    dcpu16_cycle_inc(vm, 3);
 
     ACCT_W(ev_b_addr);
 }
@@ -705,7 +733,7 @@ OP_IMPL(mod) {
         *b = *b % *a;
     }
 
-    vm->cycle += 3;
+    dcpu16_cycle_inc(vm, 3);
 
     ACCT_W(ev_a_addr);
 }
@@ -723,7 +751,7 @@ OP_IMPL(mdi) {
         *b = (short)*b % (short)*a;
     }
 
-    vm->cycle += 3;
+    dcpu16_cycle_inc(vm, 3);
 
     ACCT_W(ev_b_addr);
 }
@@ -737,7 +765,7 @@ OP_IMPL(and) {
 
     *b = *b & *a;
 
-    vm->cycle += 1;
+    dcpu16_cycle_inc(vm, 1);
 
     ACCT_W(ev_b_addr);
 }
@@ -751,7 +779,7 @@ OP_IMPL(bor) {
 
     *b = *b | *a;
 
-    vm->cycle += 1;
+    dcpu16_cycle_inc(vm, 1);
 
     ACCT_W(ev_b_addr);
 }
@@ -765,7 +793,7 @@ OP_IMPL(xor) {
 
     *b = *b ^ *a;
 
-    vm->cycle += 1;
+    dcpu16_cycle_inc(vm, 1);
 
     ACCT_W(ev_b_addr);
 }
@@ -781,7 +809,7 @@ OP_IMPL(shr) {
     *b = acc & 0xffff;
     vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     WARN("IMPLEMENT");
 
@@ -799,7 +827,7 @@ OP_IMPL(asr) {
     *b = acc & 0xffff;
     vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     WARN("IMPLEMENT");
 
@@ -818,7 +846,7 @@ OP_IMPL(shl) {
 
     vm->reg[DCPU16_REG_EX] = acc >> 16;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(ev_b_addr);
 }
@@ -834,10 +862,10 @@ OP_IMPL(ifb) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle += 1;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(ifc) {
@@ -851,10 +879,10 @@ OP_IMPL(ifc) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle += 1;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(ife) {
@@ -868,10 +896,10 @@ OP_IMPL(ife) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle += 1;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(ifn) {
@@ -885,10 +913,10 @@ OP_IMPL(ifn) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle++;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(ifg) {
@@ -902,10 +930,10 @@ OP_IMPL(ifg) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle++;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(ifa) {
@@ -919,10 +947,10 @@ OP_IMPL(ifa) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle += 1;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(ifl) {
@@ -936,10 +964,10 @@ OP_IMPL(ifl) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle++;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(ifu) {
@@ -953,10 +981,10 @@ OP_IMPL(ifu) {
         /* */
     } else {
         vm->skip_ = 1;
-        vm->cycle += 1;
+        dcpu16_cycle_inc(vm, 1);
     }
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(adx) {
@@ -974,7 +1002,7 @@ OP_IMPL(adx) {
     else
         vm->reg[DCPU16_REG_EX] = 0x0000;
 
-    vm->cycle += 3;
+    dcpu16_cycle_inc(vm, 3);
 
     ACCT_W(ev_b_addr);
 }
@@ -994,7 +1022,7 @@ OP_IMPL(sbx) {
     else
         vm->reg[DCPU16_REG_EX] = 0;
 
-    vm->cycle += 3;
+    dcpu16_cycle_inc(vm, 3);
 
     ACCT_W(ev_b_addr);
 }
@@ -1010,7 +1038,7 @@ OP_IMPL(sti) {
     vm->reg[DCPU16_REG_I] += 1;
     vm->reg[DCPU16_REG_J] += 1;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(ev_b_addr);
 }
@@ -1026,7 +1054,7 @@ OP_IMPL(std) {
     vm->reg[DCPU16_REG_I] -= 1;
     vm->reg[DCPU16_REG_J] -= 1;
 
-    vm->cycle += 2;
+    dcpu16_cycle_inc(vm, 2);
 
     ACCT_W(ev_b_addr);
 }
@@ -1229,24 +1257,11 @@ int dcpu16_interrupt(struct dcpu16 *vm, DCPU16_WORD message) {
 /* execute the next instruction */
 void dcpu16_step(struct dcpu16 *vm) {
     DCPU16_WORD opcode, b, a, instr_len, *b_data, *a_data;
-    size_t i;
     const struct opcode_entry *e;
 
     if (!vm)
         return;
 
-    /* signal interested parties that a new cycle has ticked */
-    TRACE("%s>> sending global cycle event", __func__);
-    acct_event_(vm, DCPU16_ACCT_EV_CYCLE, vm->reg[DCPU16_REG_PC]);
-
-    /* signal attached hardware */
-    for (i = 0; i < vm->hw_table_entries_; i++) {
-        if (vm->hw_table_[i].cycle) {
-            TRACE("%s>> sending cycle to %s", __func__, vm->hw_table_[i].name_);
-            vm->hw_table_[i].cycle(vm, vm->hw_table_[i].data);
-        }
-    }
-
     instruction_decode_(vm->ram, vm->reg[DCPU16_REG_PC], &opcode, &b, &b_data, &a, &a_data, &instr_len);
 
     /* consume what we decoded */
@@ -1269,7 +1284,7 @@ void dcpu16_step(struct dcpu16 *vm) {
         TRACE("++ SKIPPED %x words", instr_len);
         if (opcode >= 0x10 && opcode <= 0x17) {
             /* skipping a branch instruction? skip branch's skippable instruction as well */
-            vm->cycle += 1;
+            dcpu16_cycle_inc(vm, 1);
         } else {
             vm->skip_ = 0;
         }
@@ -1282,16 +1297,18 @@ void dcpu16_step(struct dcpu16 *vm) {
             DCPU16_WORD message;
             message = interrupt_dequeue_(vm);
 
+            TRACE("%s>> %s interrupt IA:0x%04x message:0x%04x",
+                  __func__,
+                  vm->reg[DCPU16_REG_IA] ? "servicing" : "ignoring",
+                  vm->reg[DCPU16_REG_IA],
+                  message);
             if (vm->reg[DCPU16_REG_IA]) {
-                TRACE("%s>> servicing interrupt IA:0x%04x message:0x%04x \n", __func__, vm->reg[DCPU16_REG_IA], message);
                 /* then service the next interrupt */
                 vm->interrupts_deferred_ = 1;
                 vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_PC];
                 vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_A];
                 vm->reg[DCPU16_REG_PC] = vm->reg[DCPU16_REG_IA];
                 vm->reg[DCPU16_REG_A] = message;
-            } else {
-                TRACE("%s>> ignoring interrupt IA:0", __func__);
             }
         }
     }
@@ -1312,7 +1329,7 @@ void dcpu16_state_print(struct dcpu16 *vm) {
     printf("\n");
 
     printf("(0x%08llx) %2s:0x%04x %2s:0x%04x %2s:0x%04x %2s:0x%04x [%2s]:",
-           vm->cycle,
+           vm->cycle_,
            dcpu16_reg_names[DCPU16_REG_EX], vm->reg[DCPU16_REG_EX],
            dcpu16_reg_names[DCPU16_REG_SP], vm->reg[DCPU16_REG_SP],
            dcpu16_reg_names[DCPU16_REG_PC], vm->reg[DCPU16_REG_PC],
@@ -1438,7 +1455,7 @@ void dcpu16_reset(struct dcpu16 *vm) {
 
     memset(vm->reg, 0, sizeof vm->reg);
     memset(vm->ram, 0, sizeof vm->ram);
-    vm->cycle = 0;
+    vm->cycle_ = 0;
 
     acct_event_(vm, DCPU16_ACCT_EV_RESET, 0);
 }
index f2bf787b52a589525961ec69fd75cdf03bc1c565..38203edfc52eee41553f9d28a1f9812d4b4c648f 100644 (file)
--- a/dcpu16.h
+++ b/dcpu16.h
@@ -40,6 +40,7 @@ struct dcpu16 {
     size_t hw_table_entries_;           /* hardware list maintenance */
     size_t hw_table_allocated_;         /* hardware list maintenance */
 
+    unsigned long long cycle_;          /* number of cycles this core has executed */
     unsigned int skip_ : 1;             /* skip execution of next instruction */
     unsigned int interrupts_deferred_ : 1; /* queue software interrupts */
     unsigned int on_fire_ : 1;          /* cpu is on fire */
@@ -48,7 +49,6 @@ struct dcpu16 {
     size_t interrupts_head_;            /* interrupt queue maintenance */
     size_t interrupts_tail_;            /* interrupt queue maintenance */
 
-    unsigned long long cycle;           /* number of cycles this core has executed */
     DCPU16_WORD reg[DCPU16_REG__NUM];   /* system registers, a b c x y z i j */
     DCPU16_WORD ram[DCPU16_RAM];        /* memory */
 };
@@ -116,6 +116,7 @@ void dcpu16_step(struct dcpu16 *);
 void dcpu16_delete(struct dcpu16 **);
 
 int dcpu16_interrupt(struct dcpu16 *, DCPU16_WORD);
+void dcpu16_cycle_inc(struct dcpu16 *, unsigned int);
 
 /* register callbacks to handle warning and debug messages, default is writing to stderr, may be set to null */
 void dcpu16_warn_cb_set(void (*)(char *, ...));
index 1be1810fa933720c3da6436b04be742d1633248e..e7e618393fc4e313607a24b7f9022a012656b1ae 100644 (file)
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/time.h>
 
 #ifdef HAVE_LIBPNG
 #include <setjmp.h>
@@ -39,6 +40,8 @@ static struct dcpu16_hw hw_ = {
     .data   = (struct lem1802_ *)NULL
 };
 
+#define LEM1802_POWER_ON_CYCLES 100000 /* this should vary by, let us say, 10% */
+
 #define PIX_X 160       /* pixels in display */
 #define PIX_Y 128       /* pixels in display */
 #define PIX_BORDER 16   /* border pixels from edge to first tile */
@@ -75,7 +78,8 @@ struct pixel_ {
 };
 
 struct lem1802_ {
-    long long cycle_activated; /* for tracking 'turn on delay' */
+    long long cycle_activated; /* running since */
+    long long cycles_until_active_; /* for tracking power-up delay */
 
     DCPU16_WORD video_base;
     DCPU16_WORD font_base;
@@ -90,10 +94,32 @@ struct lem1802_ {
     unsigned int blink_tally_; /* tick */
     unsigned int blink_state;
 
+    enum cycle_state_ {
+        CYCLE_IDLE,
+        CYCLE_COPY_TO_RAM,
+    } cycle_state_;
+    const DCPU16_WORD *cycle_state_copy_src_ptr_;
+    DCPU16_WORD cycle_state_copy_dst_addr_;
+    size_t cycle_state_copy_words_;
+
     int (*render)(void *, struct pixel_ *, size_t, size_t);
     void *renderer_data;
 };
 
+static
+long long power_on_cycles_(void) {
+    struct tv;
+    long long r = 0;
+
+#if WANT_DELAY_START
+    gettimeofday(&tv, NULL);
+    r += LEM1802_POWER_ON_CYCLES - (LEM1802_POWER_ON_CYCLES / 10);
+    r += tv.tv_usec % (LEM1802_POWER_ON_CYCLES / 5);
+#endif
+
+    return r;
+}
+
 static inline
 void pixel_color_(struct pixel_ *pix, DCPU16_WORD color) {
     unsigned char x;
@@ -206,8 +232,14 @@ void lem1802_pixbuf_refresh_full_(struct lem1802_ *display, DCPU16_WORD *mem) {
     TRACE("%s>> video_base:0x%04x", __func__, display->video_base);
 #endif
 
+    if (display->cycles_until_active_) {
+        /* show cute power-up sequence.. */
+        memset(display->pixbuf, 0, PIX_X * PIX_Y * sizeof *display->pixbuf);
+        return;
+    }
+
     if (display->video_base == 0) {
-        /* disconnected, blank display.  static might be fun, too */
+        /* disconnected, blank display */
         memset(display->pixbuf, 0, PIX_X * PIX_Y * sizeof *display->pixbuf);
         return;
     }
@@ -332,7 +364,8 @@ int pixbuf_render_vnc_(void *data, struct pixel_ *pixbuf, size_t x, size_t y) {
     (void)pixbuf;
 
     /* derp */
-    rfbMarkRectAsModified(s, 0, 0, x, y);
+    if (s)
+        rfbMarkRectAsModified(s, 0, 0, x, y);
 
     TRACE("%s>>", __func__);
 
@@ -359,6 +392,8 @@ void lem1802_reset_(struct dcpu16 *vm, void *data) {
     display->blink_tally_ = 0;
     display->blink_state = 0;
 
+    display->cycle_state_ = 0;
+
 #if DEBUG
     vm->trace_cb_("%s>>", __func__);
 #endif /* DEBUG */
@@ -370,10 +405,8 @@ void lem1802_cycle_(struct dcpu16 *vm, void *data) {
 
     (void)vm;
     /*
-        maybe just step through video memory (if set)
-        one word per clock..?  could just cheat and
-        use accounting callbacks..
-
+        for more cycle-accuracy, could step through video memory, if set,
+        one word per clock..
         for now just count cycles and issue a full refresh/render
         every so often
      */
@@ -393,6 +426,33 @@ void lem1802_cycle_(struct dcpu16 *vm, void *data) {
             lem1802_pixbuf_refresh_full_(display, vm->ram);
             display->render(display->renderer_data, display->pixbuf, PIX_X, PIX_Y);
     }
+
+    switch (display->cycle_state_) {
+        case CYCLE_IDLE:
+            break;
+
+        case CYCLE_COPY_TO_RAM:
+            TRACE("%s>> copy_to_ram words:%zu src:%p dst_addr:0x%04x",
+                  __func__,
+                  display->cycle_state_copy_words_,
+                  display->cycle_state_copy_src_ptr_,
+                  display->cycle_state_copy_dst_addr_);
+            vm->ram[display->cycle_state_copy_dst_addr_] = *display->cycle_state_copy_src_ptr_;
+            display->cycle_state_copy_dst_addr_++;
+            display->cycle_state_copy_src_ptr_++;
+            display->cycle_state_copy_words_--;
+            if (display->cycle_state_copy_words_ == 0) {
+                display->cycle_state_ = CYCLE_IDLE;
+            }
+            break;
+    }
+
+    if (display->cycles_until_active_) {
+        display->cycles_until_active_--;
+        if (display->cycles_until_active_ == 0) {
+            TRACE("%s>> display now active", __func__);
+        }
+    }
 }
 
 static
@@ -400,14 +460,14 @@ void lem1802_hwi_(struct dcpu16 *vm, void *data) {
     struct lem1802_ *display = (struct lem1802_ *)data;
     DCPU16_WORD reg_a = vm->reg[DCPU16_REG_A];
     DCPU16_WORD reg_b = vm->reg[DCPU16_REG_B];
-    size_t i;
 
     TRACE("%s>> A:0x%04x B:0x%04x", __func__, reg_a, reg_b);
 
     switch (reg_a) {
         case 0: /* MEM_MAP_SCREEN */
             if (display->cycle_activated == 0 && reg_b) {
-                display->cycle_activated = vm->cycle;
+                display->cycle_activated = vm->cycle_;
+                display->cycles_until_active_ = power_on_cycles_();
             }
             display->video_base = reg_b;
             if (reg_b == 0)
@@ -427,23 +487,19 @@ void lem1802_hwi_(struct dcpu16 *vm, void *data) {
             break;
 
         case 4: /* MEM_DUMP_FONT */
-            for (i = 0; i < 128 ; i++) {
-                vm->ram[reg_b] = chargen_4x8_glyphs[reg_b][0] << 8;
-                vm->ram[reg_b] |= chargen_4x8_glyphs[reg_b][1];
-                reg_b += 1;
-                vm->ram[reg_b] = chargen_4x8_glyphs[reg_b][2] << 8;
-                vm->ram[reg_b] |= chargen_4x8_glyphs[reg_b][3];
-                reg_b += 1;
-            }
-            vm->cycle += 256;
+            display->cycle_state_copy_src_ptr_ = (DCPU16_WORD *)chargen_4x8_glyphs;
+            display->cycle_state_copy_dst_addr_ = reg_b;
+            display->cycle_state_copy_words_ = 256;
+            display->cycle_state_ = CYCLE_COPY_TO_RAM;
+            dcpu16_cycle_inc(vm, 256);
             break;
 
         case 5: /* MEM_DUMP_PALETTE */
-            for (i = 0; i < 16; i++) {
-                vm->ram[reg_b] = palette_default_[i];
-                reg_b += 1;
-            }
-            vm->cycle += 16;
+            display->cycle_state_copy_src_ptr_ = palette_default_;
+            display->cycle_state_copy_dst_addr_ = reg_b;
+            display->cycle_state_copy_words_ = 16;
+            display->cycle_state_ = CYCLE_COPY_TO_RAM;
+            dcpu16_cycle_inc(vm, 16);
             break;
     }
 }
index a463f7ac94858856c5a6e6a2697f44b44811f44f..5accf2f740ed5c76baaf0235896ff845c6860612 100644 (file)
@@ -447,7 +447,7 @@ COMMAND_IMPL(run) {
 
     running_ = 1;
     gettimeofday(&run_start_tv, NULL);
-    run_cycle_start = vm->cycle;
+    run_cycle_start = vm->cycle_;
 
     memset(&act, 0, sizeof act);
     act.sa_handler = sigint_handler_;
@@ -460,7 +460,7 @@ COMMAND_IMPL(run) {
 
     while (running_) {
         gettimeofday(&start_tv, NULL);
-        cycle_start = vm->cycle;
+        cycle_start = vm->cycle_;
 
         dcpu16_step(vm);
         if (opt_.verbose > 1)
@@ -471,7 +471,7 @@ COMMAND_IMPL(run) {
         }
 
         /* how many cycles did this instr use? */
-        cycles_to_wait = vm->cycle - cycle_start;
+        cycles_to_wait = vm->cycle_ - cycle_start;
 
         if (cycles_to_wait == 0)
             continue;
@@ -500,7 +500,7 @@ COMMAND_IMPL(run) {
     run_usec = diff_tv.tv_sec * 1000000;
     run_usec += diff_tv.tv_usec;
     fprintf(stderr, "ran %llu cycles in %lds %dus (%lldus)\n",
-            vm->cycle - run_cycle_start,
+            vm->cycle_ - run_cycle_start,
             diff_tv.tv_sec,
             diff_tv.tv_usec,
             run_usec);