(-- 
   EXEunit of EX stage
   'EXEunit.balsa'
--)

import[type]

procedure EXEunit(input  EXCtrl  : EXCtrl;
                  input  sa      : 5 bits;
                  input  IDRd    : CHRd;
                  input  ReadData0, ReadData1, FOp0, FOp1, Offset32, CP0RegData : word; 
                  input  BaseAddEX : BaseAddEX;                          
                  output EXEunitRes, MemD, BaseAddMEM          : word;
                  output Shift   : shift;
                  output MulDiv : MulDiv;
                  output MEMCtrl : MEMCtrl;
                  output EXch    : ch;
                  output EXRd    : CHRd)
is local variable Offset32_R, Op0_R, Op1_R, BaseAdd_R: word
         variable EXCtrl_R : EXCtrl
         variable EXC, C   : Col
         variable sa_R     : 5 bits
         variable IDRd_R   : CHRd
         variable R, S, F, G  : bit

begin
  EXC := (0 as Col) ||
  R   := 0 ||
  S   := 0;
  loop
    begin 
      EXCtrl -> then EXCtrl_R := EXCtrl ||
                     if (#(EXCtrl.EX)[2..5] as 4 bits) = 9 then sa -> sa_R end ||
                     if EXCtrl.M.AccType /= non then Offset32 -> Offset32_R  end 
                end;
      if EXCtrl_R.EX = COR then CP0RegData -> Offset32_R end ||
      if #(EXCtrl_R.WB.wNe)[1] then IDRd   -> IDRd_R     end
    end ||

    begin
      BaseAddEX -> then BaseAdd_R := BaseAddEX.Add ||
                        C := BaseAddEX.C 
                   end;
      F := (C.EX = EXC.EX);
      G := (F or (C.MEM /= EXC.MEM))
    end ||

    select ReadData0 then Op0_R := ReadData0
    |      FOp0      then Op0_R := FOp0   
    end || 
    select ReadData1 then Op1_R := ReadData1
    |      FOp1      then Op1_R := FOp1   
    end ;

                          
    if G then
      
      if (R and F) then EXC.EX := not EXC.EX  ||
                        S      := 1 
                   else EXC    := C
      end ||

      if (EXCtrl_R.M.AccType = imm) and (EXCtrl_R.EX /= MA) then Op1_R := Offset32_R end ;

      R := 0;
       
      if #(EXCtrl_R.WB.wNe)[1] then EXRd <- IDRd_R end  ||

      case (#(EXCtrl_R.EX)[4..5] as 2 bits) of
      
          0 then 
                 if (((EXCtrl_R.EX = BEQ)   and (Op0_R = Op1_R)) or 
                    ((EXCtrl_R.EX = BNE)   and (Op0_R /= Op1_R)) or 
                    (((EXCtrl_R.EX = BGEZ) or  (EXCtrl_R.EX = BGEZAL)) and (#Op0_R[31] = 0)) or 
                    (((EXCtrl_R.EX = BLTZ) or  (EXCtrl_R.EX = BLTZAL)) and (#Op0_R[31])) or 
                    ((EXCtrl_R.EX = BGTZ)  and ((#Op0_R[31] = 0) and (Op0_R /= 0))) or 
                    ((EXCtrl_R.EX = BLEZ)  and  (#Op0_R[31] or (Op0_R = 0))) or
                     #(EXCtrl_R.EX)[3] ) then 
                       R := 1 ||
                       if (not(#(EXCtrl_R.EX)[3])) then 
                            Op0_R := ( (LShiftB {(0 as 2 bits), (#(Offset32_R)[0..29] as 30 bits)} 
                                        as word ) + BaseAdd_R as word) 
                       end ;    
                       EXch <- {Op0_R, j, EX, C} ||  
                       if #(EXCtrl_R.WB.wNe)[1] then EXEunitRes <- (BaseAdd_R + 4 as word) ||
                                                     MEMCtrl    <- {EXCtrl_R.M,EXCtrl_R.WB, C}
                                                end
              end

       | 1 then 
               if (((#(Op0_R + Op1_R as 34 bits)[32..33] as 2 bits) /= 0) and (EXCtrl_R.EX = ADD)) or
                    ((#(Op0_R - Op1_R as word)[31]) and (EXCtrl_R.EX = SUB)) then 
                      EXC.EX  := not EXC.EX ||
                      EXch <- {48, e, EX, C}  ||
                      if S then BaseAddMEM <- (BaseAdd_R - 4 as word) 
                           else BaseAddMEM <-  BaseAdd_R end  ||
                      EXEunitRes <- IDRd_R.RegData ||
                      MEMCtrl <- {{read,N}, {r, c}, C}   
               else 
                   MEMCtrl <- {EXCtrl_R.M,EXCtrl_R.WB, C}||
                   case EXCtrl_R.EX of  
                   -- Math & Logic
                     ADD, ADDU then  EXEunitRes <- (Op0_R + Op1_R as word)
                   | SUB, SUBU then  EXEunitRes <- (Op0_R - Op1_R as word)
                   | AND       then  EXEunitRes <- (Op0_R and Op1_R as word)                
                   | OR        then  EXEunitRes <- (Op0_R or Op1_R as word)
                   | XOR       then  EXEunitRes <- (Op0_R xor Op1_R as word)       
                   | NOR       then  EXEunitRes <- not (Op0_R or Op1_R as word)
                   | EXC       then  EXEunitRes <- BaseAdd_R
                   | EXCS      then  EXEunitRes <- (BaseAdd_R-4 as word) 
                   | COR       then  EXEunitRes <- Offset32_R
                   | MA        then  EXEunitRes <- (Op0_R + Offset32_R as word) ||
                                     BaseAddMEM <- BaseAdd_R ||           
                                     if (EXCtrl_R.M.AccType = write) then  MemD <- Op1_R end  
                               else  if Op0_R < Op1_R then EXEunitRes <- 1
                                                      else EXEunitRes <- 0  end
                   end
	       end

       | 2 then 
              if EXCtrl_R.EX /= NOP then 
                   if #(EXCtrl_R.EX)[3]=2 then sa_R := (#(Op0_R)[0..4] as 5 bits) end;
                   MEMCtrl <- {EXCtrl_R.M,EXCtrl_R.WB, C} ||
                   Shift <- {Op1_R, {(#(EXCtrl_R.EX )[0..1] as shiftType),  sa_R}}
              end 
          else    
              if ((#(EXCtrl_R.EX)[1..3] as 3 bits) = 3) then  MEMCtrl <- {EXCtrl_R.M,EXCtrl_R.WB, C}  end ||
              MulDiv <- {(#(EXCtrl_R.EX)[0..2] as 3 bits), Op0_R, Op1_R}
       end;
        
       S := 0                   
    else 
       if (EXCtrl_R.WB as 3 bits) = 6  then 
            EXRd    <- IDRd_R ||
            MEMCtrl <- {{non, N},{r,p}, C} ||
            EXEunitRes   <- IDRd_R.RegData          
       end
    end    
  end
end