// ************************************************************************** //
//                                                                            //
//    eses                   eses                                             //
//   eses                     eses                                            //
//  eses    eseses  esesese    eses   Embedded Systems Group                  //
//  ese    ese  ese ese         ese                                           //
//  ese    eseseses eseseses    ese   Department of Computer Science          //
//  eses   eses          ese   eses                                           //
//   eses   eseses  eseseses  eses    University of Kaiserslautern            //
//    eses                   eses                                             //
//                                                                            //
// ************************************************************************** //
// This module implements a Merge node that depending on the boolean input    //
// stream sel, the values of either x1 or x0 were selected for the output     //
// y. It is therefore a parallel if-then-else operator that demands that if   //
// one of the values x1 or x0 is selected, there must not be a value on the   //
// other stream. Clearly, one could also tolerate that there would be a value //
// on the not needed input, but in a polychronous setting, this value would be//
// lost, and therefore we better demand that there is no such value to make   //
// clear that the value is not regarded. A version that is intended in an     //
// endochronous setting should make an alternative choice.                    //
// ************************************************************************** //


macro val(x) = x.0;
macro clk(x) = x.1;

module Merge(event (bool * bool) sel,event (int * bool) x1,x0,y) {
    loop {
        // await trigger event: note that clk(y) alone is not sufficient to 
        // decide constructively about a behavior since it is not clear whether
        // the value should be taken from x1 or from x0
        if(clk(sel) or clk(x1) or clk(x0)) {
            // ensure clock consistency
            if(clk(sel)) {
                clk(x1) =  val(sel);
                clk(x0) = !val(sel);
                clk(y)  = true;
            }
            if(clk(x1)) {
                clk(sel) = true;
                val(sel) = true;
                clk(x0)  = false;
                clk(y)   = true;
            }
            if(clk(x0)) {
                clk(sel) = true;
                val(sel) = false;
                clk(x1)  = false;
                clk(y)   = true;
            }
            // produce output values
            val(y) = (val(sel) ? val(x1) : val(x0));
        }
        // negative clock information
        if(!clk(y) | !clk(sel) | !clk(x1) & !clk(x0)) {
            // ensure clock consistency
            clk(sel) = false;
            clk(x1)  = false;
            clk(x0)  = false;
            clk(y)   = false;
        }
        pause;
    }
}