diff --git a/src/emu/chan.c b/src/emu/chan.c index 638aaf4..3b56556 100644 --- a/src/emu/chan.c +++ b/src/emu/chan.c @@ -37,7 +37,7 @@ set_dirty(struct chan *chan) { if (chan->is_dirty) { /* Already dirty and allowed, no need to do anything */ - if (chan->allow_dirty_write) + if (chan->prop[CHAN_DIRTY_WRITE]) return 0; err("channel %s already dirty\n", chan->name); @@ -61,8 +61,8 @@ static int check_duplicates(struct chan *chan, struct value *v) { /* If duplicates are allowed just skip the check */ - //if (chan->oflags & CHAN_DUP) - // return 0; + if (chan->prop[CHAN_DUPLICATES]) + return 0; if (value_is_equal(&chan->last_value, v)) { err("check_duplicates %s: same value as last_value\n", @@ -82,7 +82,7 @@ chan_set(struct chan *chan, struct value value) return -1; } - if (chan->is_dirty && !chan->allow_dirty_write) { + if (chan->is_dirty && !chan->prop[CHAN_DIRTY_WRITE]) { err("chan_set %s: cannot modify dirty channel\n", chan->name); return -1; @@ -122,7 +122,7 @@ chan_push(struct chan *chan, struct value value) return -1; } - if (chan->is_dirty && !chan->allow_dirty_write) { + if (chan->is_dirty && !chan->prop[CHAN_DIRTY_WRITE]) { err("chan_push %s: cannot modify dirty channel\n", chan->name); return -1; @@ -167,7 +167,7 @@ chan_pop(struct chan *chan, struct value evalue) return -1; } - if (chan->is_dirty && !chan->allow_dirty_write) { + if (chan->is_dirty && !chan->prop[CHAN_DIRTY_WRITE]) { err("chan_pop %s: cannot modify dirty channel\n", chan->name); return -1; @@ -198,33 +198,25 @@ chan_pop(struct chan *chan, struct value evalue) return 0; } -static int +static void get_value(struct chan *chan, struct value *value) { if (chan->type == CHAN_SINGLE) { *value = chan->data.value; - return 0; + } else { + struct chan_stack *stack = &chan->data.stack; + if (stack->n > 0) + *value = stack->values[stack->n - 1]; + else + *value = value_null(); } - - struct chan_stack *stack = &chan->data.stack; - if (stack->n <= 0) { - err("get_value %s: channel stack empty\n", chan->name); - return -1; - } - - *value = stack->values[stack->n - 1]; - - return 0; } /** Reads the current value of a channel */ int chan_read(struct chan *chan, struct value *value) { - if (get_value(chan, value) != 0) { - err("chan_read %s: get_value failed\n", chan->name); - return -1; - } + get_value(chan, value); return 0; } @@ -238,13 +230,21 @@ chan_flush(struct chan *chan) return -1; } + get_value(chan, &chan->last_value); + chan->is_dirty = 0; return 0; } void -chan_dirty_write(struct chan *chan, int allow) +chan_prop_set(struct chan *chan, enum chan_prop prop, int value) { - chan->allow_dirty_write = allow; + chan->prop[prop] = value; +} + +int +chan_prop_get(struct chan *chan, enum chan_prop prop) +{ + return chan->prop[prop]; } diff --git a/src/emu/chan.h b/src/emu/chan.h index 47bd839..2c84bbd 100644 --- a/src/emu/chan.h +++ b/src/emu/chan.h @@ -16,6 +16,12 @@ enum chan_type { CHAN_MAXTYPE, }; +enum chan_prop { + CHAN_DIRTY_WRITE = 0, + CHAN_DUPLICATES, + CHAN_MAXPROP, +}; + struct chan_stack { int n; struct value values[MAX_CHAN_STACK]; @@ -35,8 +41,7 @@ struct chan { enum chan_type type; union chan_data data; int is_dirty; - int allow_dirty_write; - struct value err_value; + int prop[CHAN_MAXPROP]; struct value last_value; chan_cb_t dirty_cb; void *dirty_arg; @@ -53,7 +58,9 @@ int chan_pop(struct chan *chan, struct value expected); int chan_read(struct chan *chan, struct value *value); enum chan_type chan_get_type(struct chan *chan); int chan_flush(struct chan *chan); -void chan_dirty_write(struct chan *chan, int allow); + +void chan_prop_set(struct chan *chan, enum chan_prop prop, int value); +int chan_prop_get(struct chan *chan, enum chan_prop prop); /* Called when it becomes dirty */ void chan_set_dirty_cb(struct chan *chan, chan_cb_t func, void *arg); diff --git a/src/emu/mux.c b/src/emu/mux.c index 0c46cb6..1e7d37e 100644 --- a/src/emu/mux.c +++ b/src/emu/mux.c @@ -140,9 +140,9 @@ mux_init(struct mux *mux, } /* The output channel must accept multiple writes in the same - * propagation phase, as we may write to the input and select - * channel at the same time. */ - chan_dirty_write(output, 1); + * propagation phase while the channel is dirty, as we may write to the + * input and select channel at the same time. */ + chan_prop_set(output, CHAN_DIRTY_WRITE, 1); memset(mux, 0, sizeof(struct mux_input)); mux->select = select; diff --git a/test/unit/chan.c b/test/unit/chan.c index 6e17f82..ab49a98 100644 --- a/test/unit/chan.c +++ b/test/unit/chan.c @@ -18,7 +18,7 @@ test_dirty(void) if (chan_flush(&chan) != 0) die("chan_flush failed\n"); - chan_dirty_write(&chan, 1); + chan_prop_set(&chan, CHAN_DIRTY_WRITE, 1); if (chan_set(&chan, value_int64(3)) != 0) die("chan_set failed\n"); @@ -71,6 +71,30 @@ test_single(void) die("chan_read returned unexpected value\n"); } +static void +test_duplicate(void) +{ + struct chan chan; + chan_init(&chan, CHAN_SINGLE, "testchan"); + + if (chan_set(&chan, value_int64(1)) != 0) + die("chan_set failed\n"); + + if (chan_flush(&chan) != 0) + die("chan_flush failed\n"); + + /* Attempt to write the same value again */ + if (chan_set(&chan, value_int64(1)) == 0) + die("chan_set didn't fail\n"); + + /* Now enable duplicates */ + chan_prop_set(&chan, CHAN_DUPLICATES, 1); + + /* Then it should allow writting the same value */ + if (chan_set(&chan, value_int64(1)) != 0) + die("chan_set failed\n"); +} + //static void //test_stack(void) //{ @@ -132,6 +156,7 @@ int main(void) { test_single(); test_dirty(); + test_duplicate(); //test_stack(); return 0; }