-- ### -------------------------------------------------------------- ###
-- #									#
-- # file	: mips_dec.vbe						#
-- # date	: Mar 29 1993						#
-- # version	: v0.1							#
-- # author	: Pirouz BAZARGAN SABET					#
-- # modif	: Thu Oct 31 12:26:31 WET 1996				#
-- # descr.	: data flow description of an address decoder for DLXp.	#
-- #									#
-- ### -------------------------------------------------------------- ###

entity mips_dec is

port (
   ck          : in    bit                         ;	-- external clock
   mips_dadr   : in    bit_vector (31 downto 0)    ;	-- data address
   rw          : in    bit                         ;	-- read write
   W           : in    bit_vector ( 0     to 1)    ;	-- valid bytes
   berr	       : out   bit			   ;	-- Bus Error (activ low)
   sel_romu_n  : out   bit                         ;	-- user rom
   sel_ramu_n  : out   bit_vector ( 0     to 3)    ;	-- user ram
   sel_roms_n  : out   bit                         ;	-- system rom
   sel_rams_n  : out   bit_vector ( 0     to 3)    ;	-- system ram
   sel_timer_n : out   bit                         ;	-- timer
   sel_rome_n  : out   bit			   ;
   sel_romr_n  : out   bit		           ;
   vdd         : in    bit                         ;	--
   vss         : in    bit				--
  );

end mips_dec;

architecture FUNCTIONAL of mips_dec is

  signal notCk    : bit				     ;

  signal rams     : bit                              ;	-- select system ram
  signal ramu     : bit                              ;	-- select user ram
  signal roms     : bit                              ;	-- select system rom
  signal romu     : bit                              ;	-- select user rom
  signal romr     : bit				     ;
  signal rome     : bit				     ;
  signal timer    : bit                              ;	-- select system timer
  signal dly0_ck  : bit                              ;	-- delayed clock
  signal dly1_ck  : bit                              ;	-- delayed clock
  signal dly2_ck  : bit                              ;	-- delayed clock
  signal dly3_ck  : bit                              ;	-- delayed clock
  signal dly4_ck  : bit                              ;	-- delayed clock
  signal dly5_ck  : bit                              ;	-- delayed clock
  signal dlyd_ck  : bit                              ;	-- delayed clock

  signal bad_cry  : bit_vector ( 3 downto 0)         ;	-- adder's carry
  signal bad_add  : bit_vector ( 2 downto 0)         ;	-- bad counter's adder
  signal bad_in   : bit_vector ( 2 downto 0)         ;	-- bad counter's adder
  signal bad_cnt  : reg_vector ( 2 downto 0) register;	-- bad address counter
  signal good_cry : bit_vector ( 3 downto 0)         ;	-- adder's carry
  signal good_add : bit_vector ( 2 downto 0)         ;	-- good counter's adder
  signal good_in  : bit_vector ( 2 downto 0)         ;	-- good counter's adder
  signal good_cnt : reg_vector ( 2 downto 0) register;	-- good address counter

  constant RST    : bit_vector (31 downto 0) := X"BFC00000";	-- reset  address
  constant BAD    : bit_vector (31 downto 0) := X"004000D8";	-- bad  address
  constant GOOD   : bit_vector (31 downto 0) := X"004000D0";	-- good address
  constant BUSERR : bit_vector (31 downto 0) := X"400000C8";	-- berr address
   signal  byte : bit_vector(3 downto 0);
begin

  notCk        <= NOT(ck) ;

  dly0_ck      <= notCk;
  dly1_ck      <= dly0_ck;
  dly2_ck      <= dly1_ck;
  dly3_ck      <= dly2_ck;
  dly4_ck      <= dly3_ck;
  dly5_ck      <= dly4_ck;
  dlyd_ck      <= dly5_ck;

	-- ### ------------------------------------------------------ ###
	-- #   select on board user/system ram-rom depending on data	#
	-- # addresses :						#
	-- #								#
	-- #     0000_0000 - user ram					#
	-- #     0000_00FF - user ram					#
	-- #								#
	-- #     0000_0100 - off board ram extension			#
	-- #     7FFF_FEFF - off board ram extension			#
	-- #								#
	-- #     0040_0000 - user rom					#
	-- #     0040_00FF - user rom					#
	-- #								#
	-- #     8000_0000 - system ram					#
	-- #     8000_00FF - system ram					#
	-- #								#
	-- #     4000_00C8 - Bus Error...				#
	-- #								#
	-- #     4000_0100 - system timer				#
	-- #     4000_011F - system timer				#
	-- #								#
	-- #     8000_0200 - off board ram extension			#
	-- #     FFFF_FFFF - off board ram extension			#
	-- #								#
	-- #     8000_0000 - system rom					#
	-- #     8000_00FF - system rom					#
	-- #								#
	-- #     BFC0_0000 - reset rom					#
	-- #     BFC0_00FF - reset rom					#
	-- #								#
	-- #     8000_0080 - exception rom				#
	-- #     8000_017F - exception rom				#
	-- ### ------------------------------------------------------ ###

  with mips_dadr (31 downto 8) select
  romu  <= '1' when X"0040_00",
           '0' when others;

  with mips_dadr (31 downto 7) select
  roms  <= '1' when B"1000_0000_0000_0000_0000_0000_0",
           '0' when others;

  with mips_dadr (31 downto 8) select
  romr  <= '1' when X"bfc0_00",
           '0' when others;

  with mips_dadr (31 downto 7) select
  rome  <= '1' when B"1000_0000_0000_0000_0000_0000_1",
           '0' when others;
   with mips_dadr (31 downto 8) select
  ramu  <= '1' when X"4000_00",
           '0' when others;
  with mips_dadr (31 downto 8) select
  rams  <= '1' when X"c000_00",
           '0' when others;

  with mips_dadr (31 downto 5) select
  timer  <= '1' when B"0100_0000_0000_0000_0000_0001_000",
            '0' when others;

  berr  <= '0' when (mips_dadr = BUSERR) else '1';

	-- ### ------------------------------------------------------ ###
	-- #   assign outputs						#
	-- #     - effective selection of ram chips (on high level of	#
	-- #       clock to avoid conflicts)				#
	-- #     - effective selection of rom chips			#
	-- #     - effective selection of timer				#
	-- ### ------------------------------------------------------ ###
  
  byte <= B"1111" when (W = "11" and not(rw)) ELSE
	  B"1100" when (W = "10" and not(rw) and mips_dadr(1) = '0') ELSE
	  B"0011" when (W = "10" and not(rw) and mips_dadr(1) = '1') ELSE
	  B"1000" when (W = "01" and not(rw) and mips_dadr(1) = '0' and mips_dadr(0) ='0') ELSE
	  B"0100" when (W = "01" and not(rw) and mips_dadr(1) = '0' and mips_dadr(0) ='1') ELSE
	  B"0010" when (W = "01" and not(rw) and mips_dadr(1) = '1' and mips_dadr(0) ='0') ELSE
	  B"0001" when (W = "01" and not(rw) and mips_dadr(1) = '1' and mips_dadr(0) = '1') ELSE
	  B"1111" when (rw = '1') ELSE
	  B"0000";


  sel_ramu_n (0) <= not (ramu  and notCk and byte (0));
  sel_ramu_n (1) <= not (ramu  and notCk and byte (1));
  sel_ramu_n (2) <= not (ramu  and notCk and byte (2));
  sel_ramu_n (3) <= not (ramu  and notCk and byte (3));

  sel_rams_n (0) <= not (rams  and notCk and byte (0));
  sel_rams_n (1) <= not (rams  and notCk and byte (1));
  sel_rams_n (2) <= not (rams  and notCk and byte (2));
  sel_rams_n (3) <= not (rams  and notCk and byte (3));

  sel_timer_n    <= not (timer); -- and ck);
  assert (timer)
  report  "====   timer enabled  ===="
  severity WARNING;


--  sel_romu_n     <= not (romu  and notCk);
--  sel_roms_n     <= not (roms  and notCk);
--  sel_romr_n     <= not (romr  and notCk);
--  sel_rome_n     <= not (rome  and notCk);

   sel_romu_n     <= not (romu );
   sel_roms_n     <= not (roms );
   sel_romr_n     <= not (romr );
   sel_rome_n     <= not (rome );

	-- ### ------------------------------------------------------ ###
	-- #   watching the address bus to detect the fetch of the	#
	-- # GOOD or the BAD address (simulation aborts when the	#
	-- # instruction has been fetched 3 times)			#
	-- ### ------------------------------------------------------ ###

  bad_cry  (0)          <= '1';
  bad_cry  (3 downto 1) <= bad_cnt and bad_cry (2 downto 0);
  bad_add               <= bad_cnt xor bad_cry (2 downto 0);

  good_cry (0)          <= '1';
  good_cry (3 downto 1) <= good_cnt and good_cry (2 downto 0);
  good_add              <= good_cnt xor good_cry (2 downto 0);

  -- bad  : block (notCk = '0' and not notCk'STABLE and rw = '1' and byte = "1111")
  with ((mips_dadr = BAD) & (mips_dadr = RST)) select
      bad_in <= bad_add when B"10",
                B"000" when B"01" | B"11",
                bad_cnt when others;
  
  with ((mips_dadr = GOOD) & (mips_dadr = RST)) select
      good_in <= good_add when B"10",
                B"000" when B"01" | B"11",
                good_cnt when others;

  bad  : block (notCk = '0' and not notCk'STABLE and rw = '1')
  begin
    bad_cnt  <= guarded bad_in;
    good_cnt  <= guarded good_in;
  end block;

  assert (not (bad_cnt = "011"))
  report  "==== functional test bad  ===="
  severity ERROR;

  assert (not (good_cnt = "011"))
  report  "==== functional test good ===="
  severity ERROR;

  assert (not (mips_dadr = X"BFC00000"))
  report  "====    reset occured     ===="
  severity WARNING;

  assert (not (mips_dadr = X"80000080"))
  report  "====   exception occured  ===="
  severity WARNING;

end FUNCTIONAL;
