projects
/
dcpu16
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
support png output, buffered file writing
[dcpu16]
/
dcpu16.c
diff --git
a/dcpu16.c
b/dcpu16.c
index 772aec84917cd407884f7a281a6e0ed3be547d29..23ef53a41747da7aadb9a51baec085033d5e1bab 100644
(file)
--- a/
dcpu16.c
+++ b/
dcpu16.c
@@
-25,8
+25,9
@@
*
* TODO
* change api to print into buffers rather than stdio
*
* TODO
* change api to print into buffers rather than stdio
- * drop checks for assigning to literals -- it won't affect anything anyhow
* refactor opcode functiontables into switch statements
* 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
*/
static const char * const src_id_ = "$Id$";
*/
static const char * const src_id_ = "$Id$";
@@
-34,7
+35,7
@@
static const char * const src_id_ = "$Id$";
#define OPCODE_BASIC_BITS 4
#define OPCODE_OPERAND_BITS 6
#define OPCODE_BASIC_BITS 4
#define OPCODE_OPERAND_BITS 6
-static const char
regnames_[]
= "ABCXYZIJ";
+static const char
* const regnames_
= "ABCXYZIJ";
/* some default warning and debug reporting functions, which can be overridden by clients */
#define WARN(...) do { if (warn_cb_) warn_cb_(__VA_ARGS__); } while (0)
/* some default warning and debug reporting functions, which can be overridden by clients */
#define WARN(...) do { if (warn_cb_) warn_cb_(__VA_ARGS__); } while (0)
@@
-88,13
+89,13
@@
void dcpu16_trace_cb_set(void (*fn)(char *fmt, ...)) {
* invokes callbacks for specified event
*/
static inline
* invokes callbacks for specified event
*/
static inline
-void acct_event_(struct dcpu16 *vm, dcpu16_acct_event
_
ev, DCPU16_WORD addr) {
+void acct_event_(struct dcpu16 *vm, dcpu16_acct_event ev, DCPU16_WORD addr) {
struct dcpu16_acct_cb *cb = vm->cb_table_;
size_t i;
for (i = 0; i < vm->cb_table_entries_; i++) {
if ( (cb[i].mask & ev) )
struct dcpu16_acct_cb *cb = vm->cb_table_;
size_t i;
for (i = 0; i < vm->cb_table_entries_; i++) {
if ( (cb[i].mask & ev) )
- cb[i].fn(
ev, addr
);
+ cb[i].fn(
vm, ev, addr, cb[i].data
);
}
}
}
}
@@
-296,8
+297,8
@@
static const struct opcode_entry opcode_nbi_entries[] = {
/* basic opcodes */
/*
/* basic opcodes */
/*
- N.B. the following function does not decode values,
as the nbi
-
instructions only have one operand
.
+ N.B. the following function does not decode values,
(thus does not advance pc &c)
+
Decoding is handled by the opcode functions it calls
.
*/
OP_IMPL(_nbi_) {
/* non-basic instruction */
*/
OP_IMPL(_nbi_) {
/* non-basic instruction */
@@
-320,14
+321,16
@@
OP_IMPL(set) {
/* sets a to b */
ACCT_R(ev_b_addr);
/* sets a to b */
ACCT_R(ev_b_addr);
- ACCT_W(ev_a_addr);
- /* only set non-literal target */
- if (!lit_a) {
- *a = *b;
- }
+ /*
+ if a is a literal, it's aimed at a scratch register,
+ so it's fine to update, as it won't have any effect.
+ */
+ *a = *b;
d->cycle += 1;
d->cycle += 1;
+
+ ACCT_W(ev_a_addr);
}
OP_IMPL(add) {
}
OP_IMPL(add) {
@@
-338,9
+341,7
@@
OP_IMPL(add) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = acc;
- }
+ *a = acc;
d->o = (acc > 0xffff);
d->cycle += 2;
d->o = (acc > 0xffff);
d->cycle += 2;
@@
-356,10
+357,9
@@
OP_IMPL(sub) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = acc;
- }
+ *a = acc;
d->o = (acc > 0xffff);
d->o = (acc > 0xffff);
+
d->cycle += 2;
ACCT_W(ev_a_addr);
d->cycle += 2;
ACCT_W(ev_a_addr);
@@
-373,10
+373,9
@@
OP_IMPL(mul) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = acc;
- }
+ *a = acc;
d->o = acc >> 16;
d->o = acc >> 16;
+
d->cycle += 2;
ACCT_W(ev_a_addr);
d->cycle += 2;
ACCT_W(ev_a_addr);
@@
-390,19
+389,11
@@
OP_IMPL(div) {
ACCT_R(ev_a_addr);
if (*b == 0) {
ACCT_R(ev_a_addr);
if (*b == 0) {
- if (!lit_a) {
- *a = 0;
- }
+ *a = 0;
d->o = 0;
} else {
d->o = 0;
} else {
- unsigned int acc = *a / *b;
-
- if (!lit_a) {
- *a = acc;
- }
-
- acc = (*a << 16) / *b;
- d->o = acc;
+ *a = *a / *b;
+ d->o = (*a << 16) / *b;
}
d->cycle += 3;
}
d->cycle += 3;
@@
-418,13
+409,9
@@
OP_IMPL(mod) {
ACCT_R(ev_a_addr);
if (*b == 0) {
ACCT_R(ev_a_addr);
if (*b == 0) {
- if (!lit_a) {
- *a = 0;
- }
+ *a = 0;
} else {
} else {
- if (!lit_a) {
- *a = *a % *b;
- }
+ *a = *a % *b;
}
d->cycle += 3;
}
d->cycle += 3;
@@
-440,9
+427,8
@@
OP_IMPL(shl) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = acc;
- }
+ *a = acc;
+
d->o = acc >> 16;
d->cycle += 2;
d->o = acc >> 16;
d->cycle += 2;
@@
-458,9
+444,7
@@
OP_IMPL(shr) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = acc;
- }
+ *a = acc;
d->o = (*a << 16) >> *b;
d->cycle += 2;
d->o = (*a << 16) >> *b;
d->cycle += 2;
@@
-475,9
+459,7
@@
OP_IMPL(and) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = *a & *b;
- }
+ *a = *a & *b;
d->cycle += 1;
d->cycle += 1;
@@
-491,9
+473,7
@@
OP_IMPL(bor) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = *a | *b;
- }
+ *a = *a | *b;
d->cycle += 1;
d->cycle += 1;
@@
-507,13
+487,11
@@
OP_IMPL(xor) {
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
ACCT_R(ev_b_addr);
ACCT_R(ev_a_addr);
- if (!lit_a) {
- *a = *a ^ *b;
- }
-
- ACCT_W(ev_a_addr);
+ *a = *a ^ *b;
d->cycle += 1;
d->cycle += 1;
+
+ ACCT_W(ev_a_addr);
}
OP_IMPL(ife) {
}
OP_IMPL(ife) {
@@
-715,6
+693,8
@@
void dcpu16_step(struct dcpu16 *d) {
if (!d) return;
if (!d) return;
+ acct_event_(d, DCPU16_ACCT_EV_CYCLE, d->pc);
+
/*
PC is advanced while decoding the operands by the opcode functions.
Things like this could be organized a little better..
/*
PC is advanced while decoding the operands by the opcode functions.
Things like this could be organized a little better..
@@
-787,11
+767,12
@@
void dcpu16_dump_ram(struct dcpu16 *d, DCPU16_WORD start, DCPU16_WORD end) {
* Register callback fn to be triggered whenever event matching any events
* in bitwise mask occur.
*/
* Register callback fn to be triggered whenever event matching any events
* in bitwise mask occur.
*/
-int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event
_ mask, void (*fn)(dcpu16_acct_event_, DCPU16_WORD)
) {
+int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event
mask, dcpu16_ev_cb_t *fn, void *data
) {
struct dcpu16_acct_cb cb;
cb.mask = mask;
cb.fn = fn;
struct dcpu16_acct_cb cb;
cb.mask = mask;
cb.fn = fn;
+ cb.data = data;
if (vm->cb_table_entries_ == vm->cb_table_allocated_) {
size_t new_entries = vm->cb_table_allocated_ + 32;
if (vm->cb_table_entries_ == vm->cb_table_allocated_) {
size_t new_entries = vm->cb_table_allocated_ + 32;
@@
-811,12
+792,20
@@
int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event_ mask, void (*fn)(dcpu1
}
/* dcpu16_reset
}
/* dcpu16_reset
- *
resets a dcpu16 instance to initial state
+ *
signals cpu to reset, clearing runstate and ram, then reload any init callbacks
*/
void dcpu16_reset(struct dcpu16 *d) {
if (!d) return;
*/
void dcpu16_reset(struct dcpu16 *d) {
if (!d) return;
- memset(d, 0, sizeof *d);
+ d->cycle = 0;
+ memset(d->reg, 0, sizeof d->reg);
+ d->pc = 0;
+ d->sp = 0;
+ d->o = 0;
+ d->skip_ = 0;
+ memset(d->ram, 0, sizeof d->ram);
+
+ acct_event_(d, DCPU16_ACCT_EV_RESET, 0);
}
/* dcpu16_new
}
/* dcpu16_new