library dp_32;
use dp_32.DP32_TYPES.all ;

entity DP32 is
   generic(Tpd : TIME := 1 ns ) ;
      port(D_BUS : inout BUS_BIT_32 bus ;
           A_BUS : out   BIT_32         ;
           READ  : out   BIT            ;
           WRITE : out   BIT            ;
           FETCH : out   BIT            ;
           READY : in    BIT            ;
           Ph1   : in    BIT            ;
           Ph2   : in    BIT            ;
           RESET : in    BIT            ) ;
end DP32 ;           


architecture BEHAVIOUR of DP32 is

   subtype REG_ADDR  is NATURAL range 0 to 255    ;
   type    REG_ARRAY is array(REG_ADDR) of BIT_32 ;
   
   begin
   
 CORE:  
   process
   
      variable REG                  : REG_ARRAY                ;
      variable PC                   : BIT_32                   ;
      variable CURRENT_INSTR        : BIT_32                   ;
      variable OP                   : BIT_8                    ;
      variable R3,R2,R1             : REG_ADDR                 ;
      variable I8                   : INTEGER                  ;
      variable cc_V,cc_N,cc_Z       : BIT                      ;   
      variable temp_V,temp_N,temp_Z : BIT                      ;
      variable DISPLACEMENT         : BIT_32                   ;
      variable EFFECTIVE_ADDR       : BIT_32                   ;
      alias    cm_I                 : BIT is CURRENT_INSTR(19) ;
      alias    cm_V                 : BIT is CURRENT_INSTR(18) ;
      alias    cm_N                 : BIT is CURRENT_INSTR(17) ;
      alias    cm_Z                 : BIT is CURRENT_INSTR(16) ;
      
      
      procedure MEMORY_READ(ADDR        : in  BIT_32  ;
                            FETCH_CYCLE : in  BOOLEAN ;
                            RESULT      : out BIT_32  ) is
      begin 
      
         --start bus cycle with address output

         A_BUS <= ADDR after Tpd ;
         FETCH <= BOOL_TO_BIT(FETCH_CYCLE) after Tpd ;
         wait until Ph1 = '1' ;
         if RESET = '1' then
            return ;
         end if ;
         
         -- T1 phase

         READ <= '1' after Tpd ;
         wait until Ph1 = '1' ;
         if RESET = '1' then 
            return ;
         end if ;   
         
         --T2 phase

         loop
            wait until Ph2 = '0' ;
            if RESET = '1' then
               return ;
            end if ;
            if READY = '1' then
               RESULT := D_BUS ;
               exit ;
            end if ;
         end loop ; 
         wait until Ph1= '1' ;
         if RESET = '1' then
            return ;
         end if ;
         
         --TI phase at end of cycle

         READ <= '0' after Tpd ;
         
      end MEMORY_READ ;               
      
      procedure MEMORY_WRITE(ADDR : in BIT_32 ;
                             DATA : in BIT_32 ) is
      begin
         --start bus cycle with address output
         A_BUS <= ADDR after Tpd ;
         FETCH <= '0' after Tpd ;
         wait until Ph1 = '1' ;
         if RESET = '1' then
            return ;
         end if ;
         --T1 phase
         WRITE <= '1' after Tpd ;
         wait until Ph2 = '1' ;
         D_BUS <= DATA after Tpd ;
         wait until Ph1 = '1' ;
         if RESET = '1' then
            return ;
         end if ;
         --T2 phase
         loop
            wait until Ph2 = '0' ;
            if RESET = '1' then
               return ;
            end if ;
            exit when READY = '1' ;
         end loop ;
         wait until Ph1 = '1' ;
         if RESET = '1' then 
            return ;
         end if ;
     
         --Ti phase at and of cycle
     
         WRITE <= '0' after Tpd ;
         D_BUS <= null after Tpd ;
     
      end MEMORY_WRITE ;
      
      procedure ADD(RESULT : inout BIT_32  ;
                    OP1    : in    INTEGER ;
                    OP2    : in    INTEGER ;
                    V,N,Z  : out   BIT     ) is
      begin
      
         --positive overflow
         if OP2 > 0 and OP1 > INTEGER'low-OP2 then
            INT_TO_BITS(((INTEGER'low+OP1)+OP2)-INTEGER'high-1,RESULT) ;
            V := '1' ;
            
         --negative overflow   
         elsif OP2 < 0 and OP1 < INTEGER'low-OP2 then
            INT_TO_BITS(((INTEGER'high+OP1)+OP2)-INTEGER'low+1,RESULT) ;
            V := '0' ;
         else
            INT_TO_BITS(OP1+OP2,RESULT) ;
            V := '0' ;
         end if ;
         N := RESULT(31) ;
         Z := BOOL_TO_BIT(RESULT = X"0000_0000") ;
         
      end ADD ;            
                                                               
      procedure SUBTRACT(RESULT : inout BIT_32  ;
                         OP1    : in    INTEGER ;
                         OP2    : in    INTEGER ;
                         V,N,Z  : out   BIT     ) is
      begin
      
         --positive overflow
         if OP2 < 0 and OP1 > INTEGER'high+OP2 then
            INT_TO_BITS(((INTEGER'low+OP1)-OP2)-INTEGER'high-1,RESULT) ;
            V := '1' ;
            
         --negative overflow
         elsif OP2 > 0 and OP1 < INTEGER'low+OP2 then
            INT_TO_BITS(((INTEGER'high+OP1)-OP2)-INTEGER'low+1,RESULT) ; 
            V := '1' ;
         else
            INT_TO_BITS(OP1+OP2,RESULT) ;
            V := '0' ;
         end if ;
         N := RESULT(31) ;
         Z := BOOL_TO_BIT(RESULT = X"0000_0000") ;
      end SUBTRACT ;                                 
      
      procedure MULTIPLY(RESULT : inout BIT_32  ;
                         OP1    : in    INTEGER ;
                         OP2    : in    INTEGER ;
                         V,N,Z  : out   BIT     ) is
      begin
      
         --positive overflow
         if ((OP1>0 and OP2>0) or (OP1<0 and OP2<0))
         and (abs OP1 > INTEGER'high / abs OP2) then
            INT_TO_BITS(INTEGER'high,RESULT) ;
            V := '1' ;
            
         --negative overflow   
         elsif ((OP1>0 and OP2<0) or (OP1<0 and OP2>0))
         and ((-abs OP1) < INTEGER'low / abs OP2) then
            INT_TO_BITS(INTEGER'low,RESULT) ;
            V := '1' ;
         else                            
            INT_TO_BITS(OP1*OP2,RESULT) ;
         end if ;
         N := RESULT(31) ;
         Z := BOOL_TO_BIT(RESULT = X"0000_0000") ;
         
      end MULTIPLY ;  
      
      procedure DIVIDE(RESULT : inout BIT_32  ;
                       OP1    : in    INTEGER ;
                       OP2    : in    INTEGER ;
                       V,N,Z  : out   BIT     ) is
      begin
         if OP2= 0 then
            --positive overflow
            if OP1 >= 0 then
               INT_TO_BITS(INTEGER'high,RESULT) ;
            --negative overflow
            else
               INT_TO_BITS(INTEGER'low,RESULT) ;
            end if ;
            V := '1' ;
         else
            INT_TO_BITS(OP1/OP2,RESULT) ;
            V := '0' ;
         end if ;
         N := RESULT(31) ;
         Z := BOOL_TO_BIT(RESULT = X"0000_0000") ;
      end DIVIDE ;
               
                                    
      -- *************** DEBUT DU CODE DU PROCESS                        
                                    
      begin
      
      --check for reset active
      
      if RESET = '1' then
         READ  <= '0'  after Tpd ;
         WRITE <= '0'  after Tpd ;
         FETCH <= '0'  after Tpd ;
         D_BUS <= null after Tpd ;
         PC := X"0000_0000" ;
         wait until RESET = '0' ;
      end if ;

      --fetch next instruction
      D_BUS <= null ; -- ???? ajout‚ par bibi
      wait for 1 ns;  -- idem
      MEMORY_READ(PC,TRUE,CURRENT_INSTR) ;
      if RESET /= '1' then
      
         ADD(PC,BITS_TO_INT(PC),1,temp_V,temp_N,temp_Z) ;
         
         --decode & execute
         
         OP := CURRENT_INSTR(31 downto 24) ;
         R3 := BITS_TO_NAT(CURRENT_INSTR(23 downto 16)) ;
         R2 := BITS_TO_NAT(CURRENT_INSTR(15 downto  8)) ;
         R1 := BITS_TO_NAT(CURRENT_INSTR( 7 downto  0)) ;
         I8 := BITS_TO_INT(CURRENT_INSTR( 7 downto  0)) ;
         
         case OP is
            when OP_ADD =>
               ADD(REG(R3),BITS_TO_INT(REG(R1)),BITS_TO_INT(REG(R2)),cc_V,cc_N,
                                                                         cc_Z) ;
            when OP_ADDq =>  
               ADD(REG(R3),BITS_TO_INT(REG(R1)),I8,cc_V,cc_N,cc_Z) ;
            when OP_SUB =>
               SUBTRACT(REG(R3),BITS_TO_INT(REG(R1)),BITS_TO_INT(REG(R2)),cc_V,
                                                                   cc_N,cc_Z) ;
            when OP_SUBq =>
               SUBTRACT(REG(R3),BITS_TO_INT(REG(R1)),I8,cc_V,cc_N,cc_Z) ;
            when OP_MUL =>
               MULTIPLY(REG(R3),BITS_TO_INT(REG(R1)),BITS_TO_INT(REG(R2)),cc_V,
                                                                   cc_N,cc_Z) ;   
            when OP_MULq =>
               MULTIPLY(REG(R3),BITS_TO_INT(REG(R1)),I8,cc_V,cc_N,cc_Z) ;   
            when OP_DIV =>
               DIVIDE(REG(R3),BITS_TO_INT(REG(R1)),BITS_TO_INT(REG(R2)),cc_V,
                                                                   cc_N,cc_Z) ;
            when OP_DIVq =>
               DIVIDE(REG(R3),BITS_TO_INT(REG(R1)),I8,cc_V,cc_N,cc_Z) ;      
            when OP_Land =>
               REG(R3) := REG(R1) and REG(R2) ;
               cc_Z := BOOL_TO_BIT(REG(R3) = X"0000_0000") ;   
            when OP_Lor =>
               REG(R3) := REG(R1) or REG(R2) ;
               cc_Z := BOOL_TO_BIT(REG(R3) = X"0000_0000") ;   
            when OP_Lxor =>
               REG(R3) := REG(R1) xor REG(R2) ;
               cc_Z := BOOL_TO_BIT(REG(R3) = X"0000_0000") ;   
            when OP_Lmask =>
               REG(R3) := REG(R1) and not REG(R2) ;
               cc_Z := BOOL_TO_BIT(REG(R3) = X"0000_0000") ;   
            when OP_Ld =>
               MEMORY_READ(PC,TRUE,DISPLACEMENT) ;
               if RESET /= '1' then
                  ADD(PC,BITS_TO_INT(PC),1,temp_V,temp_N,temp_Z) ;
                  ADD(EFFECTIVE_ADDR,BITS_TO_INT(REG(R1)),
                              BITS_TO_INT(DISPLACEMENT),temp_V,temp_N,temp_Z) ;
                  MEMORY_READ(EFFECTIVE_ADDR,FALSE,REG(R3)) ;
               end if ;      
            when OP_Ldq =>
               ADD(EFFECTIVE_ADDR,BITS_TO_INT(REG(R1)),I8,temp_V,temp_N,temp_Z);
               MEMORY_READ(EFFECTIVE_ADDR,FALSE,REG(R3)) ;   
            when OP_St =>
               MEMORY_READ(EFFECTIVE_ADDR,TRUE,DISPLACEMENT) ;
               if RESET /= '1' then
                  ADD(PC,BITS_TO_INT(PC),1,temp_V,temp_N,temp_Z) ;
                  ADD(EFFECTIVE_ADDR,BITS_TO_INT(REG(R1)),
                              BITS_TO_INT(DISPLACEMENT),temp_V,temp_N,temp_Z) ;
                  MEMORY_WRITE(EFFECTIVE_ADDR,REG(R3)) ;   
               end if ; 
            when OP_Stq =>
               ADD(EFFECTIVE_ADDR,BITS_TO_INT(REG(R1)),I8,temp_V,temp_N,temp_Z);
               MEMORY_WRITE(EFFECTIVE_ADDR,REG(R3)) ;     
            when OP_Br =>
               MEMORY_READ(PC,TRUE,DISPLACEMENT) ;
               if RESET /= '1' then
                  ADD(PC,BITS_TO_INT(PC),1,temp_V,temp_N,temp_Z) ;
                  ADD(EFFECTIVE_ADDR,BITS_TO_INT(PC),BITS_TO_INT(DISPLACEMENT),
                                                        temp_V,temp_N,temp_Z) ;
                  if ((cm_V and cc_V) or (cm_N and cc_N) or (cm_Z and cc_Z)) =
                                                                      cm_I then
                     PC := EFFECTIVE_ADDR ;
                  end if ;
               end if ; 
            when OP_Bi =>
               MEMORY_READ(PC,TRUE,DISPLACEMENT) ;
               if RESET /= '1' then
                  ADD(PC,BITS_TO_INT(PC),1,temp_V,temp_N,temp_Z) ;
                  ADD(EFFECTIVE_ADDR,BITS_TO_INT(REG(R1)), 
                              BITS_TO_INT(DISPLACEMENT),temp_V,temp_N,temp_Z) ;          
                  if ((cm_V and cc_V) or (cm_N and cc_N) or (cm_Z and cc_Z)) =
                                                                      cm_I then
                     PC := EFFECTIVE_ADDR ;
                  end if ;
               end if ;
            when OP_Brq =>
               ADD(EFFECTIVE_ADDR,BITS_TO_INT(PC),I8,temp_V,temp_N,temp_Z) ;
               if ((cm_V and cc_V) or (cm_N and cc_N) or (cm_Z and cc_Z)) =
                                                                      cm_I then
                     PC := EFFECTIVE_ADDR ;
               end if ;
            when OP_Biq =>
               ADD(EFFECTIVE_ADDR,BITS_TO_INT(REG(R1)),I8,temp_V,temp_N,temp_Z);
               if ((cm_V and cc_V) or (cm_N and cc_N) or (cm_Z and cc_Z)) =
                                                                      cm_I then
                     PC := EFFECTIVE_ADDR ;
               end if ;          
            when others =>
               assert FALSE report "illegal instruction" severity WARNING ;
         end case ;               

      end if ;       
              
            
      end process ;   
      
      
end BEHAVIOUR ;
          
<div align="center"><br /><script type="text/javascript"><!--
google_ad_client = "pub-7293844627074885";
//468x60, Created at 07. 11. 25
google_ad_slot = "8619794253";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />&nbsp;</div>