#INCLUDE "/home/amu5/users/georget/Phd/Simul/Defs/defs.inc"
#USE "/home/amu5/users/georget/Phd/Simul/library"
#USE "debug.lib"

PROC DatInt (CHAN OF BUNDLE DOutd, DOutbw, DoutAin, MrrDin, PAbti,
             MrrAin,IPipeDout, Flo,IPAout, DINdout, DINcout,
             DINAout,MemCdin,MemCcin,MEMad,MEMd, MEMc,MEMa, MemAout,
             []CHAN OF DEB.MESSAGE screen,VAL INT report, evaluate)  ---4

  CHAN OF BUNDLE MWRd, MWA, PAbto, MrrDout, MDa, IPd, Fli, 
                  IPAin, DINd, DINc,DINa, MCPc, MCPa,
                  McpMctrla,MCPd:



  -----------------------------------------------------------------------
  PROC Dout(CHAN OF BUNDLE Db, DObw, MWR,Ain, Aout)

   
    CHAN OF BUNDLE Db1, DObw1, Ack1,Db2, Db3,Ack2:   


    ------------------------------------
    PROC Dataout(CHAN OF BUNDLE Dbin, DOw,Dbout)
     
      [MESGLEN]INT indata,dow,outdata:
      BOOL end:
      INT clock:    
      SEQ
        end:=FALSE 
         
        Dbin?indata        --from multiplier(either to shifter or to here)
        IF
          indata[0]<>FINISH
            SEQ          
              DOw? dow   -- from DEC2
          TRUE
            end:=TRUE

        WHILE end=FALSE
          SEQ
            clock:=indata[TIME.STAMP]
            outdata[TIME.STAMP]:= clock+ DOUT.DELAY.INT
            IF
              dow[0] = 1
                SEQ
                  outdata[0]:=(((indata[0]) /\ #000000FF) TIMES #01010101)
                                    
              TRUE
                SEQ
                  outdata[0]:=(indata[0])

            Dbout!outdata
            Dbin? indata        --from datapath(either to shifter or to here)
            IF
              indata[0]<>FINISH
                SEQ          
                  DOw? dow   -- from DEC2
              TRUE
                end:=TRUE
        Dbout!indata
    :

    ------------------------------------
    SEQ
      PAR
        two.input.stage(Db,DObw,Db1,DObw1, Ain, Ack1)
        Dataout(Db1,DObw1,Db2)
        fifo.stage(Db2,Db3, Ack1,Ack2)
        last.fifo.stage(Db3,MWR, Ack2, Aout)

  :
  -----------------------------------------------------------------------

  PROC Mrr(CHAN OF BUNDLE Din, PAbti, Dout, PAbto, Ain, Aout)

    SEQ     
      last.two.input.stage (Din, PAbti, Dout, PAbto,Ain, Aout)
  

  :
  -----------------------------------------------------------------------
  PROC  Ipipe(CHAN OF BUNDLE MDin,Fli, IN1,Flo,Ain,Aout)
    
    VAL INT num.of.stages IS IPIPE.SIZE:
    [num.of.stages-1]CHAN OF BUNDLE Data,Ctrl:
    [num.of.stages-1]CHAN OF BUNDLE Ack:
    INT i:
    SEQ
      
      PAR 
        two.input.stage(MDin,Fli,Data[0],Ctrl[0], Ain, Ack[0])
        PAR i=0 FOR num.of.stages-2 
          two.input.stage(Data[i], Ctrl[i], Data[i+1], Ctrl[i+1],
                          Ack[i], Ack[i+1])
        two.input.stage(Data[num.of.stages-2],Ctrl[num.of.stages-2],
                      IN1,Flo, Ack[num.of.stages-2], Aout)     

  :
  -----------------------------------------------------------------------

  PROC  Din(CHAN OF BUNDLE DOi, BO, D1, B1, Ain, Aout,CHAN OF DEB.MESSAGE screen, VAL INT report)
        
    CHAN OF BUNDLE DOo, IO:
    [MESGLEN]INT indata, mcpctrl, outdata, outctrl: 
    BOOL end, Lsm, Sp, bw, dpc, valid,nusr:
    [32]BOOL mcpctrlb:
    INT sh, A,word:
 
    -------------------------------
    PROC Datain(CHAN OF BUNDLE DOi, BO,DOo, IO,CHAN OF DEB.MESSAGE screen, VAL INT report)
      SEQ
    
        end:=FALSE 
         
        DOi?indata        --get data/control from destctrl, data may be garbage
        IF
          indata[0]<>FINISH
            SEQ          
              BO? mcpctrl   
          TRUE
            end:=TRUE


        WHILE end=FALSE
          SEQ
            debugmsg(report,screen, "DATINT-DATAIN: Received data",indata)
            debugmsg(report,screen, "DATINT-DATAIN: Received control",mcpctrl)
            int.to.bool(mcpctrl[0], mcpctrlb)
            init.hex(A, [mcpctrlb[4], mcpctrlb[5]])


            sh:= (A*8)
            IF
              sh > 0
                SEQ
                  word:= ((indata[0] >> sh) \/ (indata[0] << (32-sh)))
              TRUE
                word:= indata[0]


            bw:=mcpctrlb[2]

            IF
              bw = FALSE
                SEQ
                  outdata[0]:=word
              TRUE
                outdata[0]:= (((indata[0]>>sh) /\ #FF))


            get.bit(DESTPC, mcpctrl[0],dpc)
            get.bit(VALID, mcpctrl[0],valid)
            get.bit(NUSR, mcpctrl[0],nusr)
            init.hex(outctrl[0], [mcpctrlb[0], mcpctrlb[1],mcpctrlb[3]]) 

            debugmsg(report,screen, "DATINT-DATAIN: waiting to send to register", NULL1)
            outdata[TIME.STAMP]:=indata[TIME.STAMP]+DIN.DELAY.INT
            PAR
              DOo!outdata
              IO!outctrl
            debugmsg(report,screen, "DATINT-DATAIN: sent data to register", NULL1)

         
            DOi?indata     --get data/control from destctrl, data may be garbage
            IF
              indata[0]<>FINISH             
                SEQ          
                  BO? mcpctrl   
              TRUE
                end:=TRUE
        DOo!indata   --kill register
   

    :
    -------------------------------

    SEQ

      PAR
        Datain( DOi, BO, DOo, IO, screen, report)
        last.two.input.stage(DOo, IO, D1, B1, Ain, Aout)


  :
  ------------------------------------------------------------------------
  PROC DstCtl(CHAN OF BUNDLE MCPc, MDin,PAbti, IPd,IPc, IPAin, MCPa, MDa, 
                              DINd,DINc,DINa,
             CHAN OF DEB.MESSAGE screen, VAL INT report, evaluate)  ---2
 
      

    -------------------------------
    [MESGLEN]INT Ctrl,Mdata.occ, Mdata, fli, abt, Ack, Ack1,Dinctrl: 
    BOOL end, opc, valid, pcpar,abrt, finish, term:
    [6]BOOL Dinctrlb: 
    [32]BOOL Ctrlb:
    CHAN OF INT stopper:
    INT clock0:
    [10]INT delay:
    [2][OCCT.SIZE][4]INT occupancy.table:  --an array of occupancy tables!!!!

    ------------------------------
    --------------------------------  
    PROC calculate.delays()
      SEQ
        delay[0]:=SELECT
        delay[1]:=DESWAIT
        delay[2]:=CALLR
        delay[3]:=CALLA+XOR
        delay[4]:=(CALLA+XOR)+XOR
        delay[5]:=SELECT
        delay[6]:= XOR
        delay[7]:=XOR+XOR
    :
    ------------------------------
    -------------------------------------------------------------------------
    PROC  initialize.occup.tables()
      SEQ
        initialize.occup.table(occupancy.table[0], MEMCPPIPE,MEMCPPIPE.SIZE , REGISTER.DELAY)  
        initialize.occup.table(occupancy.table[1], MRRPIPE,MRRPIPE.SIZE ,REGISTER.DELAY) 
    :
    --------------------------------------------------------------------------------------


    SEQ
      calculate.delays()
      initialize.occup.tables()

      WHILE end=FALSE
        SEQ
          debugmsg(report,screen, "DATINT-DESTCTRL: waiting for control from MCP", NULL1)
          MCPc?Ctrl          -- read control from MCP memory control pipe
          debugmsg(report,screen, "DATINT-DESTCTRL: receive control from MCP",NULL1) 
          IF
            Ctrl[0] =FINISH
              SEQ
                end:=TRUE
            Ctrl[0] <>FINISH
              SEQ
                clock0:=Ctrl[TIME.STAMP]+delay[0]   --SELECT
                int.to.bool(Ctrl[0],Ctrlb)

                opc:=Ctrlb[3]
                valid:=Ctrlb[2]
                pcpar:=Ctrlb[0]

                IF
                  ----------------------------------------------------------
                  opc=TRUE              -- instruction; send to Ipipe
                    SEQ
                      debugmsg(report,screen, "DATINT-DESTCTRL: OPC TRUE waiting for ins/data from memory", Ctrl)
                      SEQ  
                        PAR
                          MDin? Mdata   --get data from mrr/from memory
                          PAbti? abt    --get  prefetch abort from mrr
                                         --if abt=TRUE data will be garbage
                                         --but it will be synchronised with 
                                         --the pc value generated by the prefetch
                        IF
                          ((((Mdata[0]<>0) AND  (Mdata[1]<>0)) AND  (Mdata[2]<>0)) AND ( Mdata[3]<>0)) 
                            SEQ
                              Mdata.occ:=Mdata
                              get.bit(ABT,abt[0], abrt)
                              init.hex(fli[0],[pcpar,abrt])
                              debugmsg(report,screen, "DATINT-DESTCTRL: OPC TRUE instruction received from Mrr for", Ctrl)
                              debugmsg(report,screen, "DATINT-DESTCTRL: OPC TRUE instruction is....", Mdata)  
                              debugmsg(report,screen, "DATINT-DESTCTRL: OPC TRUE waiting to send to Ipipe", Mdata)
                              clock0:=max(clock0,Mdata[TIME.STAMP])+delay[1] --DESWAIT
                              Mdata[TIME.STAMP]:=clock0 
                              Mdata[STALL]:=-1
                              PAR
                                IPd!Mdata     --send data+control to Ipipe      
                                IPc!fli                 
           
                              IPAin? Ack
                              debugmsg(report,screen, "DATINT-DESTCTRL: instruction forwarded to IPipe for ctrl", Ctrl)
                              debugmsg(report,screen, "DATINT-DESTCTRL: waiting to send ack to MCP and MRR", Ctrl)
                              clock0:=Ack[TIME.STAMP]
                              Ack[TIME.STAMP]:=clock0+delay[6]   --XOR
                              Ack1[TIME.STAMP]:=clock0+delay[7]   --XOR+XOR

                              calculate.occupancy(evaluate, occupancy.table[0], Ack[TIME.STAMP],Ctrl )  
                              calculate.occupancy(evaluate, occupancy.table[1], Ack1[TIME.STAMP],Mdata.occ )  
                          TRUE
                            SEQ
                              debugmsg(report,screen, "DATINT-DESTCTRL:sinking NULL instruction...", Ctrl)

                              SKIP   --sink Null instructions arriving from memory


                        PAR
                          MCPa!Ack        -- send ack to the MCP
                          MDa!Ack1         --send ack to mrr
                        debugmsg(report,screen, "DATINT-DESTCTRL: sent ack to MCP and MRR", Ctrl)

                   ----------------------------------------------------------
                  opc=FALSE             -- data
                    SEQ
                      debugmsg(report,screen, "DATINT-DESTCTRL: OPC FALSE ", Ctrl)
                      clock0:=clock0+delay[5]  --SELECT
                      IF
                        valid=TRUE                -- ok valid data
                          SEQ
                            debugmsg(report,screen, "DATINT-DESTCTRL: VALID TRUE ", Ctrl)

                            PAR
                              MDin? Mdata   -- get data from mrr/from memory
                              PAbti? abt    --get pabt from mrr

                            get.bit(ABT,abt[0], abrt)
                            Mdata.occ:=Mdata


                            Dinctrlb[0]:=Ctrlb[1]
                            Dinctrlb[1]:=(Ctrlb[2] AND (NOT abrt))
                            [Dinctrlb FROM 2 FOR 4]:=[Ctrlb FROM 4 FOR 4] 
                            init.hex(Dinctrl[0],Dinctrlb)
                            --AND gate(valid=TRUE anyway)
                            debugmsg(report,screen, "DATINT-DESTCTRL: waiting to send to DIN ", Ctrl)
                            clock0:=max(clock0,Mdata[TIME.STAMP])+delay[1] --DESWAIT
                            Mdata[TIME.STAMP]:=clock0+delay[2]   --CALL
                            Mdata[STALL]:=-1
                            PAR
                              DINd!Mdata     --send data+control to Data-input
                              DINc!Dinctrl 
                            DINa? Ack 
                            debugmsg(report,screen, "DATINT-DESTCTRL:  sent to DIN ", Ctrl)
                            clock0:=Ack[TIME.STAMP]
                            Ack[TIME.STAMP]:=clock0+delay[3]   --CALL+XOR
                            Ack1[TIME.STAMP]:=clock0+delay[4]   --CALL+XOR+XOR
                            calculate.occupancy(evaluate, occupancy.table[0], Ack[TIME.STAMP],Ctrl )  
                            calculate.occupancy(evaluate, occupancy.table[1], Ack1[TIME.STAMP],Mdata.occ )  

                            PAR                     
                              MCPa!Ack        -- send ack to the MCP
                              MDa!Ack1         --send ack to mrr

                        valid=FALSE          --don't get any data from mrr
                          SEQ                --send control and garbage data
                                             -- to the Data-input
                            debugmsg(report,screen, "DATINT-DESTCTRL: VALID FALSE ", Ctrl)
                            Dinctrlb[0]:=Ctrlb[1]
                            Dinctrlb[1]:=FALSE
                            [Dinctrlb FROM 2 FOR 4]:=[Ctrlb FROM 4 FOR 4] 
                            init.hex(Dinctrl[0],Dinctrlb)
                            Mdata.occ:=Mdata
                            Mdata[TIME.STAMP]:=clock0+delay[2]   --CALL
                            Mdata[STALL]:=-1
                            PAR
                              DINc!Dinctrl 
                              DINd!Mdata
                            DINa? Ack
                            clock0:=Ack[TIME.STAMP]
                            Ack[TIME.STAMP]:=clock0+delay[3]   --CALL+XOR

                            MCPa!Ack        -- send ack to the MCP 


      terminate(KILL, FLUSH, occupancy.table, screen, [IPd, DINd])  --flush monitoring buffers, kill neighbors
      --finish:=FALSE
      --MCPc?Ctrl       --sink new addresses arriving from MCP
      --IF
        --Ctrl[0]<>FINISH
          --SEQ
            --MCPa!Ack
        --Ctrl[0]=FINISH
          --SEQ
            --finish:=TRUE
      --WHILE finish=FALSE
        --SEQ
         -- MCPc?Ctrl
          --IF
            --Ctrl[0]<>FINISH
              --SEQ
                --MCPa!Ack
            --Ctrl[0]=FINISH
              --SEQ
                --finish:=TRUE

                     
  :
  -------------------------------------------------------------------------
  PROC MemCP (CHAN OF BUNDLE  MADcin, MADcout, Ain,Aout)   --five stage pipeline

    VAL INT num.of.stages IS MEMCPPIPE.SIZE:
    [num.of.stages-1]CHAN OF BUNDLE Data:
    [num.of.stages-1]CHAN OF BUNDLE Ack:
 
    SEQ
      
      PAR 
        fifo.stage(MADcin, Data[0], Ain, Ack[0])
        PAR i=0 FOR num.of.stages-2 
          fifo.stage(Data[i], Data[i+1], Ack[i], Ack[i+1])
        fifo.stage(Data[num.of.stages-2], MADcout, Ack[num.of.stages-2], Aout)
      
    
   

  :
  ------------------------------------------------------------------------
  PROC MemCtl(CHAN OF BUNDLE MADd, MADc, MWRd, MCPd, MCPa, MEMad,MEMd,
                              MEMc, MEMa, MADa,MWA,
              []CHAN OF DEB.MESSAGE screen, VAL INT report, evaluate)  ---2

    ------------------------------------------
    [MESGLEN]INT Addr,Ctrl, Mdata,Ack,Ack1, MADcrtl,Memctrl,Memcp,Addr.occ:
    BOOL end, wen, opc,ren, valid, dpc, term:
    [10]BOOL  MADcrtlb:
    [7]BOOL Memctrlb :
    [8]BOOL  Memcpb:
    [32 ]BOOL Ctrlb, Addrb:
    CHAN OF INT stopper:  
    [2][OCCT.SIZE][4]INT occupancy.table:  --an array of occupancy tables!!!!
    [10]INT delay:
    INT clock0, clock1, clock2, clock3, clock4, clock5:

    ------------------------------------------
    ---------------------------------------------------------  
    PROC calculate.delays()
      SEQ
        delay[0]:=SELECT
        delay[1]:=MULLERC
        delay[2]:=CALLR
        delay[3]:=SELECT
        delay[4]:=XOR
        delay[5]:=XOR+SELECT
        delay[6]:=MULLERC+CALLA
        delay[7]:=XOR
    :
    -------------------------------------------------------
    -------------------------------------------------------------------------
    PROC  initialize.occup.tables()
      SEQ
        initialize.occup.table(occupancy.table[0], MARPIPE, MARPIPE.SIZE , REGISTER.DELAY)  
        initialize.occup.table(occupancy.table[1], DOUT.PIPE, DOUT.SIZE , DOUT.DELAY)  
    :
    -------------------------------------------------------------------------



    SEQ
      calculate.delays()
      initialize.occup.tables()
      end:=FALSE
      term:=FALSE
      PAR
        --DEBUG.TIMER(stopper)
        SEQ
          MADd?Addr                  --read control info from address interface
          IF
            Addr[0]<>FINISH
              MADc? Ctrl
            TRUE
              end:=TRUE

      WHILE NOT end
        SEQ
          Addr.occ:=Addr
          clock0:=Addr[TIME.STAMP] +delay[0]    --SELECT
          int.to.bool(Ctrl[0], Ctrlb)
          int.to.bool(Addr[0], Addrb)


          [MADcrtlb FROM 0 FOR  8]:=[Ctrlb FROM 0 FOR  8]
          [MADcrtlb FROM 8 FOR  2]:=[Addrb FROM 0 FOR  2]
    
          wen:=MADcrtlb[6]
          ren:=MADcrtlb[7]
          valid:=MADcrtlb[2]
          opc:=MADcrtlb[3]
          dpc:=MADcrtlb[1]

          [Memctrlb FROM 0 FOR 7] :=[Ctrlb FROM 3 FOR 7]
          init.hex(Memctrl[0], Memctrlb)

          [Memcpb FROM 0 FOR 6]:=[MADcrtlb FROM 0 FOR 6]
          [Memcpb FROM 6 FOR 2]:=[MADcrtlb FROM 8 FOR 2]
          init.hex(Memcp[0], Memcpb)

          IF
            wen=TRUE                --write operation-get data from dout
              SEQ              
                MWRd? Mdata 
                clock0:=max(clock0, Mdata[TIME.STAMP]) +delay[1]  --MULLERC 
            wen=FALSE
              SEQ
                Mdata[TIME.STAMP]:=clock0   
                SKIP 
          clock0:=clock0+delay[2]   --CALL 
          clock1:=clock0
          clock2:=clock0       
          PAR
            ------------- memory control pipe ----------------------
            IF
              (NOT (ren AND ((NOT (opc OR dpc)) OR valid)))=FALSE
                --(ren AND (valid OR ((NOT opc) AND (NOT dpc))))    
                SEQ
                  Memcp[TIME.STAMP]:=clock1+delay[3]   --SELECT
                  Memcp[STALL]:=-1
                  debugmsg(report,screen[0], "DATINT-MEMCTRL: waiting to send control to MCP", Memcp)
                  MCPd!Memcp        --send data to Memory control pipe
                  debugmsg(report,screen[0], "DATINT-MEMCTRL: sent control to MCP wait for ack", Memcp)
                  MCPa? Ack     --wait for ack from MCP  
                  clock1:=Ack[TIME.STAMP] +delay[4] --XOR
                  debugmsg(report,screen[0], "DATINT-MEMCTRL: ack received from MCP for", Memcp)
              TRUE
                SEQ
                  clock1:=clock1+ delay[5]    --XOR+SELECT

                  SKIP 
            -------------- memory --------------------------------
            IF
              valid=TRUE            --if data is valid, send  it to memory
                SEQ
                  debugmsg(report,screen[1], "DATINT-MEMCTRL: VALID is TRUE Sending to memory...Addr", Addr)
                  debugmsg(report,screen[1], "DATINT-MEMCTRL: VALID is TRUE Sending to memory...Memctrl", Memctrl)
                  Addr[TIME.STAMP]:=clock2+delay[3]   --SELECT
                  Addr[STALL]:=-1
                  PAR
                    MEMad!Addr      --send address to memory
                    MEMd!Mdata      --send data to memory
                    MEMc!Memctrl       --send control to memory
                  MEMa? Ack1  --wait for ack from memory
                  debugmsg(report,screen[1], "DATINT-MEMCTRL: received ack from memory:", Ack1)

                  IF
                    (Ack1[0]=FINISH) AND (term=FALSE)
                      SEQ
                        terminate(NO.KILL, FLUSH, occupancy.table, screen[1], [MEMad])  
                        term:=TRUE

                    Ack1[0]<>FINISH                    --but don't kill any neighbor
                      SEQ
                        SKIP

        
                  clock2:=Ack1[TIME.STAMP] +delay[4] --XOR

              TRUE
                SEQ
                  clock2:=clock2+ delay[5]    --XOR+SELECT
                  debugmsg(report,screen[1], "DATINT-MEMCTRL: VALID is FALSE for address..", Addr)
                  SKIP
            ------------------------------------------------------ 
          clock0:=max(clock1, clock2) +delay[6] --MULLERC+CALL
          Ack[TIME.STAMP] := clock0 +delay[7]  --XOR
          Ack1[TIME.STAMP]:=  clock0 
          calculate.occupancy(evaluate, occupancy.table[1], Ack1[TIME.STAMP], Mdata )  
          calculate.occupancy(evaluate, occupancy.table[0], Ack[TIME.STAMP],Addr.occ )  

          PAR
            SEQ
              IF
                end=TRUE
                  SEQ
                    debugmsg(report,screen[1], "DATINT-MEMCTRL: end. sending FINISH Ack to AddInt:", Ack1)
                    Ack[0]:=FINISH
                TRUE
                  SKIP
              
              MADa!Ack    --send ack for the address/control (to address interface)
            IF
              wen=TRUE
                SEQ
                  MWA!Ack1    -- send ack to dout 
              TRUE
                SKIP
          IF
            end=FALSE
              SEQ
                debugmsg(report,screen[1], "DATINT-MEMCTRL: end is FALSE waiting for new address/ctrl:", NULL1)

                PAR
                  MADd?Addr    --read the next control/address info from address interface 
                  MADc? Ctrl
            end=TRUE
              SEQ
                SKIP

                        

      

      --end WHILE
      --terminate(KILL, FLUSH, occupancy.table, screen[1], [MCPd])  

      MCPd!Addr
  :
  ------------------------------------------------------------------------

    
  SEQ
    PAR

      Dout( DOutd, DOutbw, MWRd,DoutAin, MWA)


      Mrr( MrrDin, PAbti, MrrDout, PAbto, MrrAin, MDa)


      Ipipe( IPd, Fli, IPipeDout, Flo, IPAin, IPAout)


      Din(DINd,DINc, DINdout, DINcout, DINa, DINAout, screen[1], report)


      DstCtl(MCPc, MrrDout, PAbto, IPd,Fli ,IPAin, MCPa,
               MDa, DINd,DINc,DINa, screen[0], report,evaluate )

      MemCP (MCPd, MCPc, McpMctrla,MCPa)


      MemCtl(MemCdin, MemCcin, MWRd, MCPd, McpMctrla,
               MEMad,MEMd, MEMc, MEMa,MemAout, MWA,[screen FROM 2 FOR 2], report , evaluate)
    
:
  
