diff --git a/chan.c b/chan.c index 2b6c46c..3489ccf 100644 --- a/chan.c +++ b/chan.c @@ -37,15 +37,17 @@ chan_init(struct ovni_chan *chan, enum chan_track track, int row, int type, FILE chan->row = row; chan->dirty = 0; chan->track = track; + chan->lastst = -1; } static void -mark_dirty(struct ovni_chan *chan) +mark_dirty(struct ovni_chan *chan, enum chan_dirty dirty) { - assert(chan->dirty == 0); + assert(chan->dirty == CHAN_CLEAN); + assert(dirty != CHAN_CLEAN); dbg("adding dirty chan %d to list\n", chan->id); - chan->dirty = 1; + chan->dirty = dirty; DL_APPEND(*chan->update_list, chan); } @@ -75,7 +77,7 @@ chan_th_init(struct ovni_ethread *th, chan->enabled = enabled; chan->stack[chan->n++] = init_st; if(dirty) - mark_dirty(chan); + mark_dirty(chan, CHAN_DIRTY_ACTIVE); } void @@ -104,7 +106,7 @@ chan_cpu_init(struct ovni_cpu *cpu, chan->enabled = enabled; chan->stack[chan->n++] = init_st; if(dirty) - mark_dirty(chan); + mark_dirty(chan, CHAN_DIRTY_ACTIVE); } static void @@ -139,7 +141,7 @@ chan_enable(struct ovni_chan *chan, int enabled) /* Only append if not dirty */ if(!chan->dirty) { - mark_dirty(chan); + mark_dirty(chan, CHAN_DIRTY_ACTIVE); } else { @@ -179,7 +181,7 @@ chan_set(struct ovni_chan *chan, int st) /* Only append if not dirty */ if(!chan->dirty) { - mark_dirty(chan); + mark_dirty(chan, CHAN_DIRTY_VALUE); } else { @@ -215,7 +217,7 @@ chan_push(struct ovni_chan *chan, int st) chan->stack[chan->n++] = st; chan->t = *chan->clock; - mark_dirty(chan); + mark_dirty(chan, CHAN_DIRTY_VALUE); } int @@ -248,7 +250,7 @@ chan_pop(struct ovni_chan *chan, int expected_st) chan->n--; chan->t = *chan->clock; - mark_dirty(chan); + mark_dirty(chan, CHAN_DIRTY_VALUE); return st; } @@ -267,7 +269,7 @@ chan_ev(struct ovni_chan *chan, int ev) chan->ev = ev; chan->t = *chan->clock; - mark_dirty(chan); + mark_dirty(chan, CHAN_DIRTY_VALUE); } int @@ -283,6 +285,32 @@ chan_get_st(struct ovni_chan *chan) return chan->stack[chan->n-1]; } +static void +emit(struct ovni_chan *chan, int64_t t, int state) +{ + assert(chan->dirty != CHAN_CLEAN); + + /* A channel can only emit the same state as lastst if is dirty because + * it has been enabled or disabled. Otherwise is a bug (ie. you have two + * consecutive ovni events?) */ + if(chan->lastst != -1 + && chan->dirty == CHAN_DIRTY_VALUE + && chan->lastst == state) + { + /* TODO: Print the raw clock of the offending event */ + err("chan: id=%d cannot emit the same state %d twice\n", + chan->id, state); + abort(); + } + + if(chan->lastst != state) + { + prv_ev(chan->prv, chan->row, t, chan->type, state); + + chan->lastst = state; + } +} + static void emit_ev(struct ovni_chan *chan) { @@ -294,8 +322,8 @@ emit_ev(struct ovni_chan *chan) new = chan->ev; last = chan_get_st(chan); - prv_ev(chan->prv, chan->row, chan->t-1, chan->type, new); - prv_ev(chan->prv, chan->row, chan->t, chan->type, last); + emit(chan, chan->t-1, new); + emit(chan, chan->t, last); chan->ev = -1; } @@ -307,7 +335,7 @@ emit_st(struct ovni_chan *chan) st = chan_get_st(chan); - prv_ev(chan->prv, chan->row, chan->t, chan->type, st); + emit(chan, chan->t, st); } /* Emits either the current state or punctual event in the PRV file */ diff --git a/emu.c b/emu.c index ab501cb..1caa05b 100644 --- a/emu.c +++ b/emu.c @@ -82,7 +82,7 @@ print_cur_ev(struct ovni_emu *emu) static void cpu_update_tracking_chan(struct ovni_chan *cpu_chan, struct ovni_ethread *th) { - int th_enabled, cpu_enabled; + int th_enabled, cpu_enabled, st; struct ovni_chan *th_chan; assert(th); @@ -112,7 +112,9 @@ cpu_update_tracking_chan(struct ovni_chan *cpu_chan, struct ovni_ethread *th) if(th_enabled && cpu_enabled) { /* Both enabled: simply follow the same value */ - chan_set(cpu_chan, chan_get_st(th_chan)); + st = chan_get_st(th_chan); + if(chan_get_st(cpu_chan) != st) + chan_set(cpu_chan, st); } else if(th_enabled && !cpu_enabled) { @@ -192,7 +194,8 @@ emu_cpu_update_chan(struct ovni_cpu *cpu, struct ovni_chan *cpu_chan) if(!chan_is_enabled(cpu_chan)) chan_enable(cpu_chan, 1); - chan_set(cpu_chan, ST_TOO_MANY_TH); + if(chan_get_st(cpu_chan) != ST_TOO_MANY_TH) + chan_set(cpu_chan, ST_TOO_MANY_TH); } } diff --git a/emu.h b/emu.h index e31ccf5..9d9f463 100644 --- a/emu.h +++ b/emu.h @@ -170,6 +170,16 @@ enum chan_to_prv_type { CHAN_CPU = 2, }; +enum chan_dirty { + CHAN_CLEAN = 0, + + /* The channel is dirty because it has been enabled or disabled */ + CHAN_DIRTY_ACTIVE = 1, + + /* The channel is dirty because it changed the state */ + CHAN_DIRTY_VALUE = 2, +}; + /* Same order as `enum chan` */ static const int chan_to_prvtype[CHAN_MAX][3] = { /* Channel TH CPU */ @@ -212,6 +222,9 @@ struct ovni_chan { /* What state should be shown in errors */ int badst; + /* Last state emitted (-1 otherwise) */ + int lastst; + /* Punctual event: -1 if not used */ int ev; @@ -227,8 +240,8 @@ struct ovni_chan { /* Paraver row */ int row; - /* 1 if channel needs flush to PRV */ - int dirty; + /* Type of dirty */ + enum chan_dirty dirty; /* Where should the events be written to? */ FILE *prv;