// ************************************************************************** //
//                                                                            //
//    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 simple main memory that is capable to perform a   //
// load/store in each step (in case MissPenalty is 0). It is however also     //
// possible to model memory latency by increasing MissPenalty accordingly.    //
// The memory protocol is as follows:                                         //
//  (1) CPU must apply for memory access by emitting reqMem until the memory  //
//      grants access by emitting ackMem                                      //
//  (2) After that, the CPU writes adrMem, the signals readMem and writeMem   //
//      and in case of a store also dataMem until the memory has processed    //
//      the transaction which is signaled by the memory by doneMem.           //
//  (3) In case of a load instruction, the memory writes dataMem at the point //
//      of time, where dataMem holds.                                         //
// ************************************************************************** //

macro DataWidth = 8;
macro MemSize = 10;
macro MissPenalty = 0;

module MainMemory(nat ?adrMem,event bv{DataWidth} dataMem,
                  event ?readMem,?writeMem,?reqMem,!ackMem,!doneMem){
    // ----------------------------------------------------------------------
    // the following local variable defines the main memory:
    // ----------------------------------------------------------------------
    [MemSize]bv{DataWidth} Mem;

    loop {
        // ------------------------------------------------------------------
        // wait one cycle for next instruction
        // ------------------------------------------------------------------
        waitInstr: pause;
        // ------------------------------------------------------------------
        // wait until a memory request appears, and immediately acknowledge
        // ------------------------------------------------------------------
        memWait: immediate await(reqMem);
        emit(ackMem);
        // ------------------------------------------------------------------
        // model memory latency before data transfer takes place
        // ------------------------------------------------------------------
        for(i=1..MissPenalty)
            penalty: pause;
        // ------------------------------------------------------------------
        // immediate memory transaction
        // ------------------------------------------------------------------
        if(readMem & !writeMem)
            dataMem = Mem[adrMem];
        if(writeMem & !readMem)
            Mem[adrMem] = dataMem;
        // ------------------------------------------------------------------
        // immediate termination signal
        // ------------------------------------------------------------------
        emit(doneMem);
    }
}