// ************************************************************************** //
//                                                                            //
//    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                                             //
//                                                                            //
// ************************************************************************** //
// The module below implements a completely sequential matrix multiplication  //
// that only requires at most multiplication and one addition in every macro  //
// step. The disadvantage is, of course, that many steps are required to      //
// perform the matrix multiplication.                                         //
// ************************************************************************** //

macro D1 = 3;
macro D2 = 4;
macro D3 = 5;

module MatrixMultSeq(event ?req,rdy, [D1][D2]int{32} ?a, [D2][D3]int{32} ?b, [D1][D3]int{500} c){
    nat{D1+1} i;
    nat{D3+1} j; 
    nat{D2+1} k;
    loop {
        do{
            emit(rdy);
            pause;
        } while(!req);
        i = 0;
        while(i<D1) {
            j = 0;
            while(j<D3) {
                next(c[i][j]) = 0;
                pause;
                k = 0;
                while(k<D2) {
                    next(c[i][j]) = c[i][j] + a[i][k] * b[k][j];
                    next(k) = k+1;
                    pause;
                }
                next(j) = j+1;
                pause;
            }
            next(i) = i+1;
            pause;
        }
    }
}
drivenby {
    // generate input matrices
    for(i=0 .. D1-1)
        for(j=0 .. D2-1)
            a[i][j] = i*D2+j;
    for(i=0 .. D2-1)
        for(j=0 .. D3-1)
            b[i][j] = i*D3+j;
    dw1: pause;
    emit(req);
    dw2: await(rdy);
    // check correctness of matrix multiplication
    for(i=0 .. D1-1)
        for(j=0 ..D3-1)
            assert(c[i][j] == sum(k=0 .. D2-1) (a[i][k] * b[k][j]));
}