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

PROC AddressInt(CHAN OF BUNDLE MAin, MAcin,MAout,MAcout,PCToDec1,Dec1PCA,LSMout,
                 MAackin,MAAout,Pcout,Pca1,LSMa,Dec1toXPD, XPtoDec1A,XLtoDec1D,
                 Dec1XLA, MemDabt1, MemDabt0, AIDabt0,
                  []CHAN OF DEB.MESSAGE screen,VAL INT report,evaluate) --3

  CHAN OF BUNDLE MrtoIMA, MrtoIMAc,toPcreg, toLsmreg,toPcpipe,toPcreg1,Pca01,
                           FromXPD,ToXPA,ToXLD,Pca,ItoMrA,LSa,FromXLA:
  ---------------------------------------------------------------------
  PROC Pcpipe(CHAN OF BUNDLE Din, Dout, ADin,
              Aout)                      -- 2 stage pipeline

    ------------------------------------------------
    PROC first.stage( CHAN OF BUNDLE Din, Dout, ADin,
                      Aout)

      [MESGLEN]INT data, ack, data1:
      BOOL end:
      TIMER clock1:
      VAL INT delay IS (2*2343):   --2 *0.5 sec
      INT time, clock:
      [5]INT delays:
      ---------------------------------------
      PROC calculate.delays()
        SEQ
          delays[0]:=XOR+XOR
          delays[1]:=(XOR+XOR)+SELECT
      :
      ---------------------------------------


      SEQ
        calculate.delays()
        end:=FALSE
        data[0]:=0                        --the first instruction address produced; this is
        data[TIME.STAMP]:=0 + delays[0]   --XOR+XOR          --START CLOCK!!!!!!!!!!!!
        ack[TIME.STAMP]:=0   --initially
        ack[TIME.IN]:=0   --initially
        ack[STALL]:=0   --initially

        ADin!data                         --where the system actually starts its operation


        Din? data             -- the first address that is sent by the incrementer
                              --has the value 4; the first stage of the PCpipe

        data[TIME.STAMP]:=data[TIME.STAMP] + delays[1]  --XOR+XOR+SELECT

        ADin!data             --sends it back to the AddC module feeding
                              --the PCloop but it does not propagate it to the
                              --next PCpipe stage. The PC pipe will start
                              -- its normal operation with the second address
                              -- that will be sent by the incrementer with value 8
        Din?data
        IF
          data[0]<>FINISH
            SKIP
          TRUE
            end:=TRUE

        WHILE NOT end
          SEQ
            data1:=data    --This will be sent back to AddC, it concerns the PCREG pipe not the PCpipe
            data[STALL]:=-1  --Since I am the first reg in the Pcpipe my Stall is supposed to be -1
            --------check for stalls-------------
            IF
              data[STALL]=(-1)     --I am the first register in the pipe
                SEQ  
                  IF
                    ack[TIME.STAMP] > data [TIME.STAMP]   --stall
                      SEQ
                        data[STALL]:= (ack[TIME.STAMP] - data [TIME.STAMP])
                    TRUE
                      SEQ
                        data[STALL]:= 0
                        SKIP      
                  data[TIME.IN]:=(max(ack[TIME.STAMP], data[TIME.STAMP])) 
              TRUE
                SKIP       
            --------calculate timestamps---------------
            clock:=(max(ack[TIME.STAMP], data[TIME.STAMP])) + REGISTER.DELAY
            data[TIME.STAMP]:=clock

            IF
              ack[TIME.STAMP] > data1[TIME.STAMP]
                SEQ
                  clock:=clock+REGISTER.DELAY.ASU
              ack[TIME.STAMP] <= data[TIME.STAMP]
                SEQ
                  SKIP     

            data1[TIME.STAMP]:=clock

            --------send messages---------------
            --clock1?time
            --clock1 ?AFTER time PLUS delay
            PAR
              ADin!data1
              Dout !data
            PAR
              SEQ
                Din ?data
                IF
                  data[0]<>FINISH
                    SKIP
                  TRUE
                    end:=TRUE
              SEQ
                Aout ?  ack
                --debugmsg(report,screen, "ADDINT-PCPIPE 1: Received ack: ", ack)


        ADin!data     --kill AddC
    :
    ------------------------------------------------


    CHAN OF BUNDLE Data:
    CHAN OF BUNDLE Ack:

    SEQ
      PAR
        first.stage(Din,Data,ADin, Ack)
        fifo.stage(Data,Dout,Ack, Aout)
  :
  -------------------------------------------------------------------
  PROC  XPtoXL(CHAN OF BUNDLE MemDabt1, MemDabt0, AIDabt0, FromXPD, ToXPA,
                               ToXLD, FromXLA, CHAN OF DEB.MESSAGE screen,VAL INT report,evaluate)

    [MESGLEN]INT Xpc, Signal,Ackxp,Ackxl,Xpc.occ:
    BOOL abort,end:
    CHAN OF INT stopper:
    [1][OCCT.SIZE][OCCT.COL]INT occupancy.table:
    INT clock:
    -------------------------------------------------------------------------
    PROC  initialize.occup.tables()
      SEQ
        initialize.occup.table(occupancy.table[0], XPIPE, XPIPE.SIZE, REGISTER.DELAY)
    :
    -------------------------------------------------------------------------

    SEQ
      abort:=FALSE
      end:=FALSE
      initialize.occup.tables()
      PAR
        --DEBUG.TIMER(stopper)
        SEQ
          --DEBUG.MESSAGE("AddInt: coo coo!! it works!!!!!!")
          FromXPD?Xpc
          IF
            Xpc[0]<>FINISH
              SEQ
                ALT
                  MemDabt1? Signal
                    SEQ
                      abort:=TRUE
                  MemDabt0?Signal
                    SEQ
                      abort:=FALSE
                  AIDabt0?Signal
                    SEQ
                      abort:=FALSE
            TRUE
              SEQ
                end:=TRUE

      WHILE end=FALSE
        SEQ
          Xpc.occ:=Xpc
          clock:=max(Xpc[TIME.STAMP], Signal[TIME.STAMP]) + DESWAIT
          debugmsg(report,screen, "ADDINT-XPTOXL: abort received",Xpc )

          IF
            abort=FALSE
              SEQ
                Ackxp[TIME.STAMP] :=clock +XOR
                calculate.occupancy(evaluate, occupancy.table[0], Ackxp[TIME.STAMP],Xpc.occ )

                ToXPA!Ackxp   --sink!!
            abort=TRUE
              SEQ
                Xpc[TIME.STAMP]:=clock
                Xpc[STALL]:=(-1)
                ToXLD!Xpc
                FromXLA? Ackxl
                Ackxp[TIME.STAMP]:=Ackxl[TIME.STAMP] +XOR
                calculate.occupancy(evaluate, occupancy.table[0], Ackxp[TIME.STAMP],Xpc.occ )

                ToXPA!Ackxp

          FromXPD?Xpc
          IF
            Xpc[0]<>FINISH
              SEQ
                ALT
                  MemDabt1?Signal
                    SEQ
                      abort:=TRUE
                  MemDabt0?Signal
                    SEQ
                      abort:=FALSE
                  AIDabt0?Signal
                    SEQ
                      abort:=FALSE
            TRUE
              SEQ
                end:=TRUE
      terminate(evaluate, Xpc[TIME.STAMP],KILL, FLUSH, occupancy.table, screen, [ToXLD])

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

  PROC Xpipe(CHAN OF BUNDLE Din, Dout,
             Ain, Aout)   -- 3 stage pipeline



    VAL INT num.of.stages IS 3:
    [num.of.stages-1]CHAN OF BUNDLE Data:
    [num.of.stages-1]CHAN OF BUNDLE Ack:

    SEQ
      PAR
        fifo.stage(Din,Data[0],Ain, Ack[0])
        fifo.stage(Data[0],Data[1],Ack[0], Ack[1])
        fifo.stage(Data[1],Dout,Ack[1], Aout)



  :
  ------------------------------------------------------------------
  PROC LSMreg(CHAN OF BUNDLE Din, Dout,Ain, Aout)            -- A simple register

    SEQ
      last.fifo.stage(Din, Dout,Ain, Aout)

  :
  ------------------------------------------------------------------
  PROC XLatch(CHAN OF BUNDLE Din, Dout, Ain, Aout)            -- A simple register

    SEQ
      last.fifo.stage(Din, Dout,Ain, Aout)

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

  PROC Marreg(CHAN OF BUNDLE D1in, D2in,D1out, D2out,MAo,MAco,
              Ain, Aout)

    PROC mar.input.stage (CHAN OF BUNDLE D1in, D2in,D1out, D2out,MAo,MAco,
                          Ain, Aout)

      [MESGLEN]INT data1, data2,ack:
      BOOL end:
      INT clock:
      SEQ
        ack:=[0,0,0,0]   --initially

        end:=FALSE
        D1in?data1
        IF
          data1[0]<>FINISH
            D2in?data2
          TRUE
            end:=TRUE

        WHILE NOT end
          SEQ
            --------check for stalls-------------
            ------data1 carries timing information
            IF
              data1[STALL]=(-1)     --I am the first register in the pipe
                SEQ  
                  IF
                    ack[TIME.STAMP] > data1 [TIME.STAMP]   --stall
                      SEQ
                        data1[STALL]:= (ack[TIME.STAMP] - data1 [TIME.STAMP])
                    TRUE
                      SEQ
                        data1[STALL]:= 0
                        SKIP      
                  data1[TIME.IN]:=(max(ack[TIME.STAMP], data1[TIME.STAMP]))
 
              TRUE
                SKIP        


            --------calculate timestamps---------------
            clock:=(max (ack[TIME.STAMP], data1[TIME.STAMP])) + REGISTER.DELAY
            data1[TIME.STAMP]:=clock
            data2[TIME.STAMP]:=clock


            IF
              ack[TIME.STAMP] > data1[TIME.STAMP]
                SEQ
                  clock:=clock+REGISTER.DELAY.ASU
              ack[TIME.STAMP] <= data1[TIME.STAMP]
                SEQ
                  SKIP     

            ack[TIME.STAMP]:=clock
            --------send messages---------------

            PAR
              Ain!ack
              D1out ! data1
              D2out ! data2
              MAo   !data1   -- send data and control to DatInt(MemCtrl)
              MAco  !data2

            PAR
              SEQ
                D1in ?data1
                IF
                  data1[0]<>FINISH
                    D2in?data2
                  TRUE
                    end:=TRUE
              Aout ?  ack

        D1out!data1   -- kill incrementer
        MAo!data1     -- kill DatInt
    :
    -----------------------------------------------------
    SEQ
      mar.input.stage (D1in, D2in,D1out, D2out,MAo,MAco,Ain, Aout)
  :
  ------------------------------------------------------------------
  PROC Pcreg0(CHAN OF BUNDLE Din, Dout,Ain, Aout)      -- A simple register

    SEQ
      fifo.stage(Din, Dout,Ain, Aout)

  :
  ----------------------------------------------------------------------
  PROC Pcreg1(CHAN OF BUNDLE Din, Dout,Ain, Aout)            -- A simple register

    SEQ
      fifo.stage(Din, Dout,Ain, Aout)

  :
  ----------------------------------------------------------------------
  PROC Incrementer(CHAN OF BUNDLE MAi,MAci,toPcreg,toLsmreg,
                   MAa,Pca,LSa,MAa1,[]CHAN OF DEB.MESSAGE screen,VAL INT report)
    --------------------------------------
    [MESGLEN]INT data, Ctrl, ack,ack1:
    BOOL Lsm, Opc,end, term:
    [9]BOOL Ctrlb:
    [5]INT delay:
    INT clock0, clock1, clock2, x1,x2:
    ---------------------------------------
    PROC calculate.delays()
      SEQ
        delay[0]:=SELECT
        delay[1]:=INCREMENT.DELAY+SELECT
        delay[2]:=XOR
        delay[3]:=MULLERC
    :
    ---------------------------------------

    SEQ
      term:=FALSE
      end:=FALSE
      ack[TIME.STAMP]:=0
      calculate.delays()
      MAi? data            -- read from AddC
      IF
        data[0]<>FINISH
          SEQ
            MAci?Ctrl  --if not end of simulation, read control too
        TRUE
          end:=TRUE
      WHILE NOT end
        SEQ
          clock0:=data[TIME.STAMP]
          debugmsg(report,screen[0], "ADDINT-INCREMENTER: Received new data from AddC ", data)

          PAR
            SEQ
              MAa? ack                --ack from memory

              debugmsg(report,screen[0], "ADDINT-INCREMENTER: Received ack from memory ", ack)
            SEQ
              int.to.bool(Ctrl[0],Ctrlb)
              debugmsg(report,screen[1], "ADDINT-INCREMENTER: Ctrl IS  ", Ctrl)

              --************************************************
              clock2:=clock0+delay[0]   --SELECT
              data[TIME.STAMP]:=clock2+delay[1]  --INCREMENT.DELAY+SELECT
              data[STALL]:=(-1)
              --************************************************

              IF
                (Ctrlb[8]=TRUE) --AND (term=FALSE)             -- increment address
                  SEQ
                    data[0]:=data[0]+4

                    IF
                      Ctrlb[3]=TRUE
                        SEQ
                          toPcreg!data
                          debugmsg(report,screen[1], "ADDINT-INCREMENTER: Propagate to PcPipe", data)
                      Ctrlb[3]=FALSE
                        SEQ
                          toLsmreg!data
                          debugmsg(report,screen[1], "ADDINT-INCREMENTER: Propagate to LsmPipe", data)
                TRUE
                  SKIP

              IF
                ((Ctrlb[8]=TRUE) AND (Ctrlb[3]=TRUE) ) --AND (term=FALSE))      --ack from Pcreg
                  SEQ

                    Pca? ack1
                    debugmsg(report,screen[1], "ADDINT-INCREMENTER: Received ack from Pcpipe for", data)
                ((Ctrlb[8]=TRUE) AND (Ctrlb[3]=FALSE) ) --AND (term=FALSE))     --ack from Lsmreg
                  SEQ
                    LSa? ack1
                TRUE
                  SEQ
                    --debugmsg(report,screen, "ADDINT-INCREMENTER: Dont propagate ", data[0])
                    ack1[TIME.STAMP]:=0
                    SKIP
              clock2:=ack1[TIME.STAMP]+delay[3]     --XOR


          --------------------------------------
          IF
            ack[0]=FINISH
              SEQ
                term:=TRUE
                debugmsg(report,screen[1], "ADDINT-INCREMENTER: Ack FINISH has been received", data)

            ack[0]<>FINISH
              SEQ
                SKIP
          -------------------------------------
          x1:=max(ack[TIME.STAMP], (ack1[TIME.STAMP]+delay[3]))
          ack[TIME.STAMP]:=x1
          SEQ
            SEQ

              MAa1!ack                     --ack to Marreg
              debugmsg(report,screen[0], "ADDINT-INCREMENTER: ack to AddC ", ack)
          MAi?data            -- read from AddC
          --debugmsg(report,screen, "ADDINT-INCREMENTER: Received data from MAR ", data[0])
          IF
            data[0]<>FINISH
              SEQ
                MAci?Ctrl  --if not end of simulation, read control too
            TRUE
              end:=TRUE

      --end WHILE
      PAR                          --KILL LSMREG, PCPIPE
        toPcreg!data
        toLsmreg!data



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


  PAR

    Marreg( MAin, MAcin, MrtoIMA, MrtoIMAc, MAout,MAcout,MAackin, ItoMrA)


    Incrementer( MrtoIMA, MrtoIMAc,toPcreg,toLsmreg, MAAout,
                Pca,LSa,ItoMrA,[screen[1], screen[2]],report)

    Pcreg0( toPcreg, toPcreg1, Pca, Pca01)

    Pcreg1( toPcreg1, toPcpipe, Pca01, Pca1)

    Pcpipe(toPcpipe, PCToDec1, Pcout, Dec1PCA)

    Xpipe (Dec1toXPD, FromXPD,XPtoDec1A, ToXPA)

    XPtoXL(MemDabt1, MemDabt0, AIDabt0, FromXPD, ToXPA, ToXLD, FromXLA,screen[0],report,evaluate)

    XLatch(ToXLD, XLtoDec1D,FromXLA, Dec1XLA )

    LSMreg (toLsmreg, LSMout, LSa, LSMa)


:
