use std.textio.all, work.bv_arithmetic.all;

architecture bench of dlx_test is

  ----------------------------------------------------------------

  -- dlx_types
  
  subtype dlx_word is bit_vector(0 to 31); -- bit 0 is msb
  subtype dlx_halfword is bit_vector(0 to 15); -- bot 0 is msb
  subtype dlx_byte is bit_vector(0 to 7); -- bit 0 is msb
  
  type dlx_word_array is array (positive range <>) of dlx_word;
--  function resolve_dlx_word (values : in dlx_word_array) return dlx_word;
--  subtype dlx_word_bus is resolve_dlx_word dlx_word;
  
  subtype dlx_address is bit_vector(31 downto 0);  -- bit 0 is lsb
  
  ----------------------------------------------------------------

  -- mem_types

  type mem_width is (width_byte, width_halfword, width_word);

  ----------------------------------------------------------------

  -- alu_types

  type alu_func is (alu_add, alu_addu, alu_sub, alu_subu, 
      	      	    alu_and, alu_or, alu_xor,
      	      	    alu_sll, alu_srl, alu_sra, 
		    alu_pass_s1, alu_pass_s2);

  ----------------------------------------------------------------

  -- dlx_instr

  subtype dlx_opcode is bit_vector(0 to 5);
  subtype dlx_sp_func is bit_vector(0 to 5);
  subtype dlx_shamt is bit_vector(0 to 4);
  subtype dlx_fp_func is bit_vector(0 to 4);
  subtype dlx_reg_addr is bit_vector(0 to 4);
  subtype dlx_immed16 is bit_vector(0 to 15);
  subtype dlx_immed26 is bit_vector(0 to 25);
  
  subtype dlx_opcode_num is natural range 0 to 63;
  subtype dlx_sp_func_num is natural range 0 to 63;
  subtype dlx_fp_func_num is natural range 0 to 31;
      
  constant op_num_special	: dlx_opcode_num := 2#000000#;
  constant op_num_fparith	: dlx_opcode_num := 2#000001#;
  constant op_num_j		: dlx_opcode_num := 2#000010#;
  constant op_num_jal		: dlx_opcode_num := 2#000011#;
  constant op_num_beqz		: dlx_opcode_num := 2#000100#;
  constant op_num_bnez		: dlx_opcode_num := 2#000101#;
  constant op_num_bfpt		: dlx_opcode_num := 2#000110#;
  constant op_num_bfpf		: dlx_opcode_num := 2#000111#;
  constant op_num_addi		: dlx_opcode_num := 2#001000#;
  constant op_num_addui		: dlx_opcode_num := 2#001001#;
  constant op_num_subi		: dlx_opcode_num := 2#001010#;
  constant op_num_subui		: dlx_opcode_num := 2#001011#;
  constant op_num_andi		: dlx_opcode_num := 2#001100#;
  constant op_num_ori		: dlx_opcode_num := 2#001101#;
  constant op_num_xori		: dlx_opcode_num := 2#001110#;
  constant op_num_lhi		: dlx_opcode_num := 2#001111#;

  constant op_num_rfe		: dlx_opcode_num := 2#010000#;
  constant op_num_trap		: dlx_opcode_num := 2#010001#;
  constant op_num_jr		: dlx_opcode_num := 2#010010#;
  constant op_num_jalr		: dlx_opcode_num := 2#010011#;
  constant op_num_undef_14	: dlx_opcode_num := 2#010100#;
  constant op_num_undef_15	: dlx_opcode_num := 2#010101#;
  constant op_num_undef_16	: dlx_opcode_num := 2#010110#;
  constant op_num_undef_17	: dlx_opcode_num := 2#010111#;
  constant op_num_seqi		: dlx_opcode_num := 2#011000#;
  constant op_num_snei		: dlx_opcode_num := 2#011001#;
  constant op_num_slti		: dlx_opcode_num := 2#011010#;
  constant op_num_sgti		: dlx_opcode_num := 2#011011#;
  constant op_num_slei		: dlx_opcode_num := 2#011100#;
  constant op_num_sgei		: dlx_opcode_num := 2#011101#;
  constant op_num_undef_1E	: dlx_opcode_num := 2#011110#;
  constant op_num_undef_1F	: dlx_opcode_num := 2#011111#;

  constant op_num_lb		: dlx_opcode_num := 2#100000#;
  constant op_num_lh		: dlx_opcode_num := 2#100001#;
  constant op_num_undef_22	: dlx_opcode_num := 2#100010#;
  constant op_num_lw		: dlx_opcode_num := 2#100011#;
  constant op_num_lbu		: dlx_opcode_num := 2#100100#;
  constant op_num_lhu		: dlx_opcode_num := 2#100101#;
  constant op_num_lf		: dlx_opcode_num := 2#100110#;
  constant op_num_ld		: dlx_opcode_num := 2#100111#;
  constant op_num_sb		: dlx_opcode_num := 2#101000#;
  constant op_num_sh		: dlx_opcode_num := 2#101001#;
  constant op_num_undef_2A	: dlx_opcode_num := 2#101010#;
  constant op_num_sw		: dlx_opcode_num := 2#101011#;
  constant op_num_undef_2C	: dlx_opcode_num := 2#101100#;
  constant op_num_undef_2D	: dlx_opcode_num := 2#101101#;
  constant op_num_sf		: dlx_opcode_num := 2#101110#;
  constant op_num_sd		: dlx_opcode_num := 2#101111#;

  constant op_num_sequi		: dlx_opcode_num := 2#110000#;
  constant op_num_sneui		: dlx_opcode_num := 2#110001#;
  constant op_num_sltui		: dlx_opcode_num := 2#110010#;
  constant op_num_sgtui		: dlx_opcode_num := 2#110011#;
  constant op_num_sleui		: dlx_opcode_num := 2#110100#;
  constant op_num_sgeui		: dlx_opcode_num := 2#110101#;
  constant op_num_undef_36	: dlx_opcode_num := 2#110110#;
  constant op_num_undef_37	: dlx_opcode_num := 2#110111#;
  constant op_num_undef_38	: dlx_opcode_num := 2#111000#;
  constant op_num_undef_39	: dlx_opcode_num := 2#111001#;
  constant op_num_undef_3A	: dlx_opcode_num := 2#111010#;
  constant op_num_undef_3B	: dlx_opcode_num := 2#111011#;
  constant op_num_undef_3C	: dlx_opcode_num := 2#111100#;
  constant op_num_undef_3D	: dlx_opcode_num := 2#111101#;
  constant op_num_undef_3E	: dlx_opcode_num := 2#111110#;
  constant op_num_undef_3F	: dlx_opcode_num := 2#111111#;

  constant sp_func_num_slli		: dlx_sp_func_num := 2#000000#;
  constant sp_func_num_undef_01		: dlx_sp_func_num := 2#000001#;
  constant sp_func_num_srli	 	: dlx_sp_func_num := 2#000010#;
  constant sp_func_num_srai	 	: dlx_sp_func_num := 2#000011#;
  constant sp_func_num_sll	 	: dlx_sp_func_num := 2#000100#;
  constant sp_func_num_undef_05		: dlx_sp_func_num := 2#000101#;
  constant sp_func_num_srl	 	: dlx_sp_func_num := 2#000110#;
  constant sp_func_num_sra	 	: dlx_sp_func_num := 2#000111#;
  constant sp_func_num_undef_08		: dlx_sp_func_num := 2#001000#;
  constant sp_func_num_undef_09		: dlx_sp_func_num := 2#001001#;
  constant sp_func_num_undef_0A		: dlx_sp_func_num := 2#001010#;
  constant sp_func_num_undef_0B		: dlx_sp_func_num := 2#001011#;
  constant sp_func_num_undef_0C		: dlx_sp_func_num := 2#001100#;
  constant sp_func_num_undef_0D		: dlx_sp_func_num := 2#001101#;
  constant sp_func_num_undef_0E		: dlx_sp_func_num := 2#001110#;
  constant sp_func_num_undef_0F		: dlx_sp_func_num := 2#001111#;

  constant sp_func_num_sequ		: dlx_sp_func_num := 2#010000#;
  constant sp_func_num_sneu		: dlx_sp_func_num := 2#010001#;
  constant sp_func_num_sltu		: dlx_sp_func_num := 2#010010#;
  constant sp_func_num_sgtu		: dlx_sp_func_num := 2#010011#;
  constant sp_func_num_sleu		: dlx_sp_func_num := 2#010100#;
  constant sp_func_num_sgeu		: dlx_sp_func_num := 2#010101#;
  constant sp_func_num_undef_16		: dlx_sp_func_num := 2#010110#;
  constant sp_func_num_undef_17		: dlx_sp_func_num := 2#010111#;
  constant sp_func_num_mult		: dlx_sp_func_num := 2#011000#;
  constant sp_func_num_multu		: dlx_sp_func_num := 2#011001#;
  constant sp_func_num_div		: dlx_sp_func_num := 2#011010#;
  constant sp_func_num_divu		: dlx_sp_func_num := 2#011011#;
  constant sp_func_num_undef_1C		: dlx_sp_func_num := 2#011100#;
  constant sp_func_num_undef_1D		: dlx_sp_func_num := 2#011101#;
  constant sp_func_num_undef_1E		: dlx_sp_func_num := 2#011110#;
  constant sp_func_num_undef_1F		: dlx_sp_func_num := 2#011111#;

  constant sp_func_num_add		: dlx_sp_func_num := 2#100000#;
  constant sp_func_num_addu		: dlx_sp_func_num := 2#100001#;
  constant sp_func_num_sub		: dlx_sp_func_num := 2#100010#;
  constant sp_func_num_subu		: dlx_sp_func_num := 2#100011#;
  constant sp_func_num_and		: dlx_sp_func_num := 2#100100#;
  constant sp_func_num_or		: dlx_sp_func_num := 2#100101#;
  constant sp_func_num_xor		: dlx_sp_func_num := 2#100110#;
  constant sp_func_num_undef_27		: dlx_sp_func_num := 2#100111#;
  constant sp_func_num_seq		: dlx_sp_func_num := 2#101000#;
  constant sp_func_num_sne		: dlx_sp_func_num := 2#101001#;
  constant sp_func_num_slt		: dlx_sp_func_num := 2#101010#;
  constant sp_func_num_sgt		: dlx_sp_func_num := 2#101011#;
  constant sp_func_num_sle		: dlx_sp_func_num := 2#101100#;
  constant sp_func_num_sge		: dlx_sp_func_num := 2#101101#;
  constant sp_func_num_undef_2E		: dlx_sp_func_num := 2#101110#;
  constant sp_func_num_undef_2F		: dlx_sp_func_num := 2#101111#;
  
  constant sp_func_num_movi2s		: dlx_sp_func_num := 2#110000#;
  constant sp_func_num_movs2i		: dlx_sp_func_num := 2#110001#;
  constant sp_func_num_movf		: dlx_sp_func_num := 2#110010#;
  constant sp_func_num_movd		: dlx_sp_func_num := 2#110011#;
  constant sp_func_num_movfp2i		: dlx_sp_func_num := 2#110100#;
  constant sp_func_num_movi2fp		: dlx_sp_func_num := 2#110101#;
  constant sp_func_num_undef_36		: dlx_sp_func_num := 2#110110#;
  constant sp_func_num_undef_37		: dlx_sp_func_num := 2#110111#;
  constant sp_func_num_undef_38		: dlx_sp_func_num := 2#111000#;
  constant sp_func_num_undef_39		: dlx_sp_func_num := 2#111001#;
  constant sp_func_num_undef_3A		: dlx_sp_func_num := 2#111010#;
  constant sp_func_num_undef_3B		: dlx_sp_func_num := 2#111011#;
  constant sp_func_num_undef_3C		: dlx_sp_func_num := 2#111100#;
  constant sp_func_num_undef_3D		: dlx_sp_func_num := 2#111101#;
  constant sp_func_num_undef_3E		: dlx_sp_func_num := 2#111110#;
  constant sp_func_num_undef_3F		: dlx_sp_func_num := 2#111111#;
  
  constant fp_func_num_addf		: dlx_fp_func_num := 2#00000#;
  constant fp_func_num_subf		: dlx_fp_func_num := 2#00001#;
  constant fp_func_num_multf		: dlx_fp_func_num := 2#00010#;
  constant fp_func_num_divf		: dlx_fp_func_num := 2#00011#;
  constant fp_func_num_addd		: dlx_fp_func_num := 2#00100#;
  constant fp_func_num_subd		: dlx_fp_func_num := 2#00101#;
  constant fp_func_num_multd		: dlx_fp_func_num := 2#00110#;
  constant fp_func_num_divd		: dlx_fp_func_num := 2#00111#;
  constant fp_func_num_cvtf2d		: dlx_fp_func_num := 2#01000#;
  constant fp_func_num_cvtf2i		: dlx_fp_func_num := 2#01001#;
  constant fp_func_num_cvtd2f		: dlx_fp_func_num := 2#01010#;
  constant fp_func_num_cvtd2i		: dlx_fp_func_num := 2#01011#;
  constant fp_func_num_cvti2f		: dlx_fp_func_num := 2#01100#;
  constant fp_func_num_cvti2d		: dlx_fp_func_num := 2#01101#;
  constant fp_func_num_undef_0E		: dlx_fp_func_num := 2#01110#;
  constant fp_func_num_undef_0F		: dlx_fp_func_num := 2#01111#;
  
  constant fp_func_num_eqf		: dlx_fp_func_num := 2#10000#;
  constant fp_func_num_nef		: dlx_fp_func_num := 2#10001#;
  constant fp_func_num_ltf		: dlx_fp_func_num := 2#10010#;
  constant fp_func_num_gtf		: dlx_fp_func_num := 2#10011#;
  constant fp_func_num_lef		: dlx_fp_func_num := 2#10100#;
  constant fp_func_num_gef		: dlx_fp_func_num := 2#10101#;
  constant fp_func_num_undef_16		: dlx_fp_func_num := 2#10110#;
  constant fp_func_num_undef_17		: dlx_fp_func_num := 2#10111#;
  constant fp_func_num_eqd		: dlx_fp_func_num := 2#11000#;
  constant fp_func_num_ned		: dlx_fp_func_num := 2#11001#;
  constant fp_func_num_ltd		: dlx_fp_func_num := 2#11010#;
  constant fp_func_num_gtd		: dlx_fp_func_num := 2#11011#;
  constant fp_func_num_led		: dlx_fp_func_num := 2#11100#;
  constant fp_func_num_ged		: dlx_fp_func_num := 2#11101#;
  constant fp_func_num_undef_1E		: dlx_fp_func_num := 2#11110#;
  constant fp_func_num_undef_1F		: dlx_fp_func_num := 2#11111#;

  subtype instr_name is string(1 to 8);
  type opcode_name_array is array (dlx_opcode_num) of instr_name;
  type sp_func_name_array is array (dlx_sp_func_num) of instr_name;
  type fp_func_name_array is array (dlx_fp_func_num) of instr_name;
  
  -- constant opcode_names : opcode_name_array;
  -- constant sp_func_names : sp_func_name_array;
  -- constant fp_func_names : fp_func_name_array;

  constant opcode_names : opcode_name_array :=
    ( "SPECIAL ", "FPARITH ", "J       ", "JAL     ",
      "BEQZ    ", "BNEZ    ", "BFPT    ", "BFPF    ",
      "ADDI    ", "ADDUI   ", "SUBI    ", "SUBUI   ",
      "ANDI    ", "ORI     ", "XORI    ", "LHI     ",
      "RFE     ", "TRAP    ", "JR      ", "JALR    ",
      "UNDEF_14", "UNDEF_15", "UNDEF_16", "UNDEF_17",
      "SEQI    ", "SNEI    ", "SLTI    ", "SGTI    ",
      "SLEI    ", "SGEI    ", "UNDEF_1E", "UNDEF_1F",
      "LB      ", "LH      ", "UNDEF_22", "LW      ",
      "LBU     ", "LHU     ", "LF      ", "LD      ",
      "SB      ", "SH      ", "UNDEF_2A", "SW      ",
      "UNDEF_2C", "UNDEF_2D", "SF      ", "SD      ",
      "SEQUI   ", "SNEUI   ", "SLTUI   ", "SGTUI   ",
      "SLEUI   ", "SGEUI   ", "UNDEF_36", "UNDEF_37",
      "UNDEF_38", "UNDEF_39", "UNDEF_3A", "UNDEF_3B",
      "UNDEF_3C", "UNDEF_3D", "UNDEF_3E", "UNDEF_3F" );
      
  constant sp_func_names : sp_func_name_array :=
    ( "SLLI    ", "UNDEF_01", "SRLI    ", "SRAI    ",
      "SLL     ", "UNDEF_05", "SRL     ", "SRA     ",
      "UNDEF_08", "UNDEF_09", "UNDEF_0A", "UNDEF_0B",
      "UNDEF_0C", "UNDEF_0D", "UNDEF_0E", "UNDEF_0F",
      "SEQU    ", "SNEU    ", "SLTU    ", "SGTU    ",
      "SLEU    ", "SGEU    ", "UNDEF_16", "UNDEF_17",
      "MULT    ", "MULTU   ", "DIV     ", "DIVU    ",
      "UNDEF_1C", "UNDEF_1D", "UNDEF_1E", "UNDEF_1F",
      "ADD     ", "ADDU    ", "SUB     ", "SUBU    ",
      "AND     ", "OR      ", "XOR     ", "UNDEF_27",
      "SEQ     ", "SNE     ", "SLT     ", "SGT     ",
      "SLE     ", "SGE     ", "UNDEF_2E", "UNDEF_2F",
      "MOVI2S  ", "MOVS2I  ", "MOVF    ", "MOVD    ",
      "MOVFP2I ", "MOVI2FP ", "UNDEF_36", "UNDEF_37",
      "UNDEF_38", "UNDEF_39", "UNDEF_3A", "UNDEF_3B",
      "UNDEF_3C", "UNDEF_3D", "UNDEF_3E", "UNDEF_3F" );

  constant fp_func_names : fp_func_name_array :=
    ( "ADDF    ", "SUBF    ", "MULTF   ", "DIVF    ",
      "ADDD    ", "SUBD    ", "MULTD   ", "DIVD    ",
      "CVTF2D  ", "CVTF2I  ", "CVTD2F  ", "CVTD2I  ",
      "CVTI2F  ", "CVTI2D  ", "UNDEF_0E", "UNDEF_0F",
      "EQF     ", "NEF     ", "LTF     ", "GTF     ",
      "LEF     ", "GEF     ", "UNDEF_16", "UNDEF_17",
      "EQD     ", "NED     ", "LTD     ", "GTD     ",
      "LED     ", "GED     ", "UNDEF_1E", "UNDEF_1F" );

  type immed_size is (immed_size_16, immed_size_26);
  
  subtype reg_index is natural range 0 to 31;
  
  constant link_reg : reg_index := 31;

  procedure write_reg (L : inout line; reg : reg_index) is
    
  begin
    write(L, 'R');
    write(L, reg);
  end write_reg;

  procedure write_special_reg (L : inout line; reg : reg_index) is
    
  begin
    case reg is
      when 0 =>
      	write(L, string'("IAR"));
      when others =>
      	write(L, string'("SR"));
      	write(L, reg);
    end case;
  end write_special_reg;

  procedure write_instr (L : inout line; instr : in dlx_word) is

    alias instr_opcode : dlx_opcode is instr(0 to 5);
    alias instr_sp_func : dlx_sp_func is instr(26 to 31);
    alias instr_shamt : dlx_shamt is instr(21 to 25);
    alias instr_fp_func : dlx_fp_func is instr(27 to 31);
    alias instr_rs1 : dlx_reg_addr is instr(6 to 10);
    alias instr_rs2 : dlx_reg_addr is instr(11 to 15);
    alias instr_Itype_rd : dlx_reg_addr is instr(11 to 15);
    alias instr_Rtype_rd : dlx_reg_addr is instr(16 to 20);
    alias instr_immed16 : dlx_immed16 is instr(16 to 31);
    alias instr_immed26 : dlx_immed26 is instr(6 to 31);

    variable instr_opcode_num : dlx_opcode_num := bv_to_natural(instr_opcode);
    variable instr_sp_func_num : dlx_sp_func_num := bv_to_natural(instr_sp_func);
    variable instr_fp_func_num : dlx_fp_func_num := bv_to_natural(instr_fp_func);
    variable rs1 : reg_index := bv_to_natural(instr_rs1);
    variable rs2 : reg_index := bv_to_natural(instr_rs2);
    variable Itype_rd : reg_index := bv_to_natural(instr_Itype_rd);
    variable Rtype_rd : reg_index := bv_to_natural(instr_Rtype_rd);

  begin
    if (instr_opcode_num /= op_num_special) and (instr_opcode_num /= op_num_fparith) then
      write(L, opcode_names(instr_opcode_num));
      write(L, ' ');
    end if;
    case instr_opcode_num is
      when op_num_special =>
      	write(L, sp_func_names(instr_sp_func_num));
      	write(L, ' ');
      	case instr_sp_func_num is
	  when sp_func_num_slli | sp_func_num_srli | sp_func_num_srai =>
	    write_reg(L, Rtype_rd); write(L, string'(", "));
	    write_reg(L, rs2); write(L, string'(", "));
	    write(L, bv_to_natural(instr_shamt));
          when sp_func_num_sll | sp_func_num_srl | sp_func_num_sra |
	      sp_func_num_sequ | sp_func_num_sneu | sp_func_num_sltu |
              sp_func_num_sgtu | sp_func_num_sleu | sp_func_num_sgeu |
              sp_func_num_mult | sp_func_num_multu | sp_func_num_div | sp_func_num_divu |
              sp_func_num_add | sp_func_num_addu | sp_func_num_sub | sp_func_num_subu |
              sp_func_num_and | sp_func_num_or | sp_func_num_xor |
              sp_func_num_seq | sp_func_num_sne | sp_func_num_slt |
              sp_func_num_sgt | sp_func_num_sle | sp_func_num_sge =>
	    write_reg(L, Rtype_rd); write(L, string'(", "));
	    write_reg(L, rs1); write(L, string'(", "));
	    write_reg(L, rs2);
	  when sp_func_num_movi2s =>
	    write_special_reg(L, Rtype_rd); write(L, string'(", "));
	    write_reg(L, rs1);
	  when sp_func_num_movs2i =>
	    write_reg(L, Rtype_rd); write(L, string'(", "));
	    write_special_reg(L, rs1);
	  when sp_func_num_movf | sp_func_num_movd |
	      sp_func_num_movfp2i | sp_func_num_movi2fp =>
	    write_reg(L, Rtype_rd); write(L, string'(", "));
	    write_reg(L, rs1);
	  when others =>
	    null;
	end case;
      when op_num_fparith =>
      	write(L, fp_func_names(instr_fp_func_num));
      	write(L, ' ');
      	case instr_fp_func_num is
	  when fp_func_num_addf | fp_func_num_subf | fp_func_num_multf | fp_func_num_divf |
              fp_func_num_addd | fp_func_num_subd | fp_func_num_multd | fp_func_num_divd =>
	    write_reg(L, Rtype_rd); write(L, string'(", "));
	    write_reg(L, rs1); write(L, string'(", "));
	    write_reg(L, rs2);
	  when fp_func_num_cvtf2d | fp_func_num_cvtf2i |
              fp_func_num_cvtd2f | fp_func_num_cvtd2i |
              fp_func_num_cvti2f | fp_func_num_cvti2d =>
      	    write_reg(L, Rtype_rd); write(L, string'(", "));
	    write_reg(L, rs1);
  	  when fp_func_num_eqf | fp_func_num_nef | fp_func_num_ltf |
              fp_func_num_gtf | fp_func_num_lef | fp_func_num_gef |
  	      fp_func_num_eqd | fp_func_num_ned | fp_func_num_ltd |
              fp_func_num_gtd | fp_func_num_led | fp_func_num_ged =>
      	    write_reg(L, rs1); write(L, string'(", "));
	    write_reg(L, rs2);
      	  when others =>
	    null;
	end case;
      when op_num_j  | op_num_jal =>
      	write(L, bv_to_integer(instr_immed26));
      when op_num_beqz | op_num_bnez =>
      	write_reg(L, rs1); write(L, string'(", "));
	write(L, bv_to_integer(instr_immed16));
      when op_num_bfpt | op_num_bfpf =>
      	write(L, bv_to_integer(instr_immed16));
      when op_num_addi | op_num_subi |
      	  op_num_seqi | op_num_snei | op_num_slti | op_num_sgti | op_num_slei | op_num_sgei =>
      	write_reg(L, Itype_rd); write(L, string'(", "));
      	write_reg(L, rs1); write(L, string'(", "));
	write(L, bv_to_integer(instr_immed16));
      when op_num_addui | op_num_subui | op_num_andi | op_num_ori | op_num_xori |
      	  op_num_sequi | op_num_sneui | op_num_sltui | op_num_sgtui | op_num_sleui | op_num_sgeui =>
      	write_reg(L, Itype_rd); write(L, string'(", "));
      	write_reg(L, rs1); write(L, string'(", "));
	write(L, bv_to_natural(instr_immed16));
      when op_num_lhi =>
      	write_reg(L, Itype_rd); write(L, string'(", "));
	write(L, bv_to_natural(instr_immed16));
      when op_num_rfe =>
      	null;
      when op_num_trap =>
      	write(L, bv_to_natural(instr_immed26));
      when op_num_jr | op_num_jalr =>
      	write_reg(L, rs1);
      when op_num_lb | op_num_lh | op_num_lw |
      	  op_num_lbu | op_num_lhu | op_num_lf | op_num_ld =>
      	write_reg(L, Itype_rd); write(L, string'(", "));
	write(L, bv_to_integer(instr_immed16)); write(L, '(');
	write_reg(L, rs1); write(L, ')');
      when op_num_sb | op_num_sh | op_num_sw | op_num_sf | op_num_sd =>
      	write(L, bv_to_integer(instr_immed16));
	write(L, '('); write_reg(L, rs1); write(L, string'("), "));
	write_reg(L, Itype_rd);
      when others =>
      	null;
    end case;
    
  end write_instr;

  ----------------------------------------------------------------

  -- dlx_test_bench

  constant Tpw : Time := 8 ns;
  constant Tps : Time := 2 ns;
  constant clock_period : Time := 2*(Tpw+Tps);

  constant mem_size : positive := 256;

  signal phi1, phi2, reset : bit;
  signal a : dlx_address;
  -- signal d : dlx_word_bus bus;
  signal d_write, d_read : dlx_word;
  signal halt : bit;
  signal width : mem_width;
  signal write_enable, mem_enable, ifetch, ready : bit;
  
  -- internal signals for the dlx processor
  
  -- signal s1_bus, s2_bus : dlx_word_bus; -- MGC bug workaround
  signal s1_bus, s2_bus : dlx_word;
  signal s1_1, s1_2, s1_3, s1_4, s1_5, s1_6, s1_7, s1_8 : dlx_word;
  signal s2_1, s2_2, s2_3, s2_4, s2_5, s2_6, s2_7, s2_8 : dlx_word;
  --
  signal dest_bus : dlx_word;
  signal alu_latch_en : bit;
  signal alu_function : alu_func;
  signal alu_zero, alu_negative, alu_overflow : bit;
  signal reg_s1_addr, reg_s2_addr, reg_dest_addr : dlx_reg_addr;
  signal reg_file_out1, reg_file_out2, reg_file_in : dlx_word;
  signal reg_write : bit;
  signal a_out_en, a_latch_en : bit;
  signal b_out_en, b_latch_en : bit;
  signal c_latch_en : bit;
  signal temp_out_en1, temp_out_en2, temp_latch_en : bit;
  signal iar_out_en1, iar_out_en2, iar_latch_en : bit;
  signal pc_out_en1, pc_out_en2, pc_latch_en : bit;
  signal pc_to_mem : dlx_word;
  signal mar_out_en1, mar_out_en2, mar_latch_en : bit;
  signal mar_to_mem : dlx_word;
  signal mem_addr_mux_sel : bit;
  signal mdr_out_en1, mdr_out_en2, mdr_out_en3, mdr_latch_en : bit;
  signal mdr_in : dlx_word;
  signal mdr_mux_sel : bit;
  signal current_instruction : dlx_word;
  signal ir_latch_en : bit;
  signal ir_immed_sel1, ir_immed_sel2 : immed_size;
  signal ir_immed_unsigned1, ir_immed_unsigned2 : bit;
  signal ir_immed_en1, ir_immed_en2 : bit;
  
begin -- bench of dlx_test

  ----------------------------------------------------------------

  -- cg : clock_gen
  --   port map (phi1, phi2, reset);
    
  reset_driver: 
    reset <= '1', '0' after 2*clock_period + Tpw+Tps;

  clock_driver : process
  begin
    if halt = '0' then
      phi1 <= '1', '0' after Tpw;
      phi2 <= '1' after Tpw+Tps, '0' after Tpw+Tps+Tpw;
      wait for clock_period;
    else
      wait;
    end if;
  end process clock_driver;
  
  ----------------------------------------------------------------

  -- mem : memory
  --   port map (phi1, phi2, a, d_write, d_read, width, write_enable, mem_enable, ready);
    
  mem : process
    
    constant low_address : natural := 0;
    constant high_address : natural := mem_size - 1;
    
    subtype byte is bit_vector(0 to 7);
    subtype ls_2_bits is bit_vector(1 downto 0);
    
    type memory_array is
      array (natural range low_address to high_address) of byte;
      
    variable mem : memory_array
      -- initially loaded with prog1.out
      := ( 
      	   0 => x"24",  1 => x"01",  2 => x"00",  3 => x"02",
      	   4 => x"ac",  5 => x"01",  6 => x"00",  7 => x"28",
      	   8 => x"24",  9 => x"02", 10 => x"00", 11 => x"0a",
      	  12 => x"2c", 13 => x"42", 14 => x"00", 15 => x"01",
      	  16 => x"14", 17 => x"40", 18 => x"ff", 19 => x"f8",
      	  20 => x"8c", 21 => x"01", 22 => x"00", 23 => x"28",
      	  24 => x"2c", 25 => x"21", 26 => x"00", 27 => x"01",
      	  28 => x"ac", 29 => x"01", 30 => x"00", 31 => x"28",
      	  32 => x"14", 33 => x"20", 34 => x"ff", 35 => x"e4",
      	  36 => x"44", 37 => x"00", 38 => x"00", 39 => x"00",
      	  others => x"00"
	 );

    variable aligned_a : dlx_address;
    variable address : natural;
    
  begin  -- mem
    -- initialize outputs
    --
    -- d <= null;
    --
    ready <= '0';
    -- 
    -- process memory cycles
    --
    loop
      --
      -- wait for a command, valid on leading edge of phi2
      --
      wait until phi2 = '1' and mem_enable = '1';
      --
      -- decode address and perform command if selected
      --
      if address >= low_address and address <= high_address then
      	if write_enable = '1' then -- write cycle
      	  --
      	  -- align address to accessed unit
      	  --
      	  aligned_a := a;
      	  case width is
      	    when width_word =>
	      aligned_a(1 downto 0) := b"00";
	    when width_halfword =>
	      aligned_a(0) := '0';
	    when width_byte =>
	      null;
      	  end case;
      	  address := bv_to_natural(aligned_a);
	  case width is
	    when width_word =>
	      -- mem(address) := d(0 to 7);
	      -- mem(address+1) := d(8 to 15);
	      -- mem(address+2) := d(16 to 23);
	      -- mem(address+3) := d(24 to 31);
	      mem(address) := d_write(0 to 7);
	      mem(address+1) := d_write(8 to 15);
	      mem(address+2) := d_write(16 to 23);
	      mem(address+3) := d_write(24 to 31);
	    when width_halfword =>
	      if a(1) = '0' then  -- ms half word
	      	-- mem(address) := d(0 to 7);
		-- mem(address+1) := d(8 to 15);
	      	mem(address) := d_write(0 to 7);
		mem(address+1) := d_write(8 to 15);
	      else  -- ls half word
	      	-- mem(address) := d(16 to 23);
		-- mem(address+1) := d(24 to 31);
	      	mem(address) := d_write(16 to 23);
		mem(address+1) := d_write(24 to 31);
	      end if;
	    when width_byte =>
	      case ls_2_bits'(a(1 downto 0)) is
	      	when b"00" =>
		  -- mem(address) := d(0 to 7);
		  mem(address) := d_write(0 to 7);
		when b"01" =>
		  -- mem(address) := d(8 to 15);
		  mem(address) := d_write(8 to 15);
		when b"10" =>
		  -- mem(address) := d(16 to 23);
		  mem(address) := d_write(16 to 23);
		when b"11" =>
		  -- mem(address) := d(24 to 31);
		  mem(address) := d_write(24 to 31);
	      end case;
	  end case;
	else -- read cycle
	  aligned_a := a;
	  aligned_a(1 downto 0) := b"00";
	  address := bv_to_natural(aligned_a);
      	  -- d <= mem(address) & mem(address+1) & mem(address+2) & mem(address+3);
	  d_read <= mem(address) & mem(address+1) & mem(address+2) & mem(address+3);
	end if;
	ready <= '1';
	wait until phi1 = '1';
	ready <= '0';
	if write_enable = '0' then  -- was read
	  -- d <= null;
	  --
	end if;
      end if;
    end loop;
  end process mem;

  ----------------------------------------------------------------

  -- bus_monitor : dlx_bus_monitor
  --   port map (phi1, phi2, reset, a, d_write, d_read, 
  --     	      halt, width, write_enable, mem_enable, ifetch, ready);

  monitor: process
  
    variable write_command, instr_fetch : boolean;
    variable L : line;
    
  begin
    monitor_loop : loop
      --
      -- wait for a command, valid on leading edge of phi2
      --
      wait until phi2 = '1' and mem_enable = '1';
      --
      -- capture the command information
      --
      write_command := write_enable = '1';
      instr_fetch := ifetch = '1';
      write(L, string'("DLX_bus_monitor: Command "));
      if write_command then
      	write(L, string'("D-write to "));
      elsif instr_fetch then
      	write(L, string'("I-fetch from "));
      else
      	write(L, string'("D-read from "));
      end if;
      write_hex(L, a);
      case width is
      	when width_word =>
	  write(L, string'(", word"));
	when width_halfword =>
	  write(L, string'(", halfword"));
	when width_byte =>
	  write(L, string'(", byte"));
      end case;
      if write_command then
      	write(L, string'(", data "));
	write_hex(L, d_write);
      end if;
      writeline(output, L);
      --
      -- wait for the response from memory
      --
      loop 
      	wait until phi2 = '0';
	if reset = '1' then
	  exit monitor_loop;
	end if;
	exit when ready = '1';
      end loop;
      write(L, string'("DLX_bus_monitor: Ready"));
      if not write_command then
      	if instr_fetch then
	  write(L, string'(", instruction "));
	  write_hex(L, d_read);
	  write(L, string'(" [ "));
	  write_instr(L, d_read);
	  write(L, string'(" ]"));
	else
      	  write(L, string'(", data "));
	  write_hex(L, d_read);
	end if;
      end if;
      writeline(output, L);
    end loop monitor_loop;
    --
    -- get here when reset is asserted
    --
    assert reset = '1'
      report "reset code reached with reset = '0'" severity error;
    write(L, string'("DLX_bus_monitor: Reset"));
    writeline(output, L);
    wait until phi2 = '0' and reset = '0';
    write(L, string'("DLX_bus_monitor: End Reset"));
    writeline(output, L);
    --
    -- process monitor now starts again from beginning
    --
  end process monitor;

  ----------------------------------------------------------------

  -- proc : dlx
  --   port map (phi1, phi2, reset, a, d_write, d_read, 
  --     	      halt, width, write_enable, mem_enable, ifetch, ready);

  ----------------------------------------------------------------

--   the_alu : alu
--     port map (s1 => s1_bus, s2 => s2_bus, result => dest_bus,
--               latch_en => alu_latch_en, func => alu_function,
--               zero => alu_zero, negative => alu_negative, overflow => alu_overflow);

  the_alu : process (s1_bus, s2_bus, alu_latch_en, alu_function)

    variable temp_result : dlx_word;
    variable temp_overflow : boolean;

  begin
    if alu_latch_en = '1' then
      case alu_function is
      	when alu_pass_s1 =>
      	  temp_result := s1_bus;
      	when alu_pass_s2 =>
      	  temp_result := s2_bus;
      	when alu_and =>
       	  temp_result := s1_bus and s2_bus;
      	when alu_or =>
       	  temp_result := s1_bus or s2_bus;
      	when alu_xor =>
       	  temp_result := s1_bus xor s2_bus;
      	when alu_sll =>
       	  temp_result := bv_sll(s1_bus, bv_to_natural(s2_bus));
      	when alu_srl =>
       	  temp_result := bv_srl(s1_bus, bv_to_natural(s2_bus));
      	when alu_sra =>
       	  temp_result := bv_sra(s1_bus, bv_to_natural(s2_bus));
      	when alu_add =>
      	  bv_add(s1_bus, s2_bus, temp_result, temp_overflow);
      	when alu_addu =>
      	  bv_addu(s1_bus, s2_bus, temp_result, temp_overflow);
      	when alu_sub =>
      	  bv_sub(s1_bus, s2_bus, temp_result, temp_overflow);
      	when alu_subu =>
      	  bv_subu(s1_bus, s2_bus, temp_result, temp_overflow);
      end case;
      dest_bus <= temp_result;
      alu_zero <= bit'val(boolean'pos(temp_result = dlx_word'(X"0000_0000")));
      alu_negative <= temp_result(0);
      alu_overflow <= bit'val(boolean'pos(temp_overflow));
    end if;
  end process the_alu;

  ----------------------------------------------------------------

--   the_reg_file : reg_file
--     port map (a1 => reg_s1_addr, q1 => reg_file_out1,
--               a2 => reg_s2_addr, q2 => reg_file_out2,
--               a3 => reg_dest_addr, d3 => reg_file_in,
--               write_en => reg_write);

  the_reg_file : process (reg_s1_addr, reg_s2_addr, reg_dest_addr, reg_file_in, reg_write)

    constant all_zeros : dlx_word := X"0000_0000";

    type register_array is array (reg_index range 1 to 31) of dlx_word;
    
    variable register_file : register_array;
    variable reg_index1, reg_index2, reg_index3 : reg_index;

  begin
    -- do write first if enabled
    --
    if reg_write = '1' then
      reg_index3 := bv_to_natural(reg_dest_addr);
      if reg_index3 /= 0 then
      	register_file(reg_index3) := reg_file_in;
      end if;
    end if;
    --
    -- read port 1
    --
    reg_index1 := bv_to_natural(reg_s1_addr);
    if reg_index1 /= 0 then
      reg_file_out1 <= register_file(reg_index1);
    else
      reg_file_out1 <= all_zeros;
    end if;
    --
    -- read port 2
    --
    reg_index2 := bv_to_natural(reg_s2_addr);
    if reg_index2 /= 0 then
      reg_file_out2 <= register_file(reg_index2);
    else
      reg_file_out2 <= all_zeros;
    end if;
  end process the_reg_file;

  ----------------------------------------------------------------

--   c_reg : latch
--     port map (d => dest_bus, q => reg_file_in, latch_en => c_latch_en);

  c_reg : process (dest_bus, c_latch_en)
  begin
    if c_latch_en = '1' then
      reg_file_in <= dest_bus;
    end if;
  end process c_reg;

  ----------------------------------------------------------------

--   a_reg : reg_1_out
--     port map (d => reg_file_out1, q => s1_1,
--               latch_en => a_latch_en, out_en => a_out_en);

  a_reg : process (reg_file_out1, a_latch_en, a_out_en)

    variable latched_value : dlx_word;

  begin
    if a_latch_en = '1' then
      latched_value := reg_file_out1;
    end if;
    if a_out_en = '1' then
      s1_1 <= latched_value;
    else
      -- s1_1 <= null;			  -- work around MGC bug
      s1_1 <= X"0000_0000";
      --
    end if;
  end process a_reg;

  ----------------------------------------------------------------

--   b_reg : reg_1_out
--     port map (d => reg_file_out2, q => s2_1,
--               latch_en => b_latch_en, out_en => b_out_en);

  b_reg : process (reg_file_out2, b_latch_en, b_out_en)

    variable latched_value : dlx_word;

  begin
    if b_latch_en = '1' then
      latched_value := reg_file_out2;
    end if;
    if b_out_en = '1' then
      s2_1 <= latched_value;
    else
      -- s2_1 <= null;			  -- work around MGC bug
      s2_1 <= X"0000_0000";
      --
    end if;
  end process b_reg;

  ----------------------------------------------------------------

--   temp_reg : reg_2_out
--     port map (d => dest_bus, q1 => s1_2, q2 => s2_2,
--               latch_en => temp_latch_en,
--               out_en1 => temp_out_en1, out_en2 => temp_out_en2);

  temp_reg : process (dest_bus, temp_latch_en, temp_out_en1, temp_out_en2)

    variable latched_value : dlx_word;

  begin
    if temp_latch_en = '1' then
      latched_value := dest_bus;
    end if;
    if temp_out_en1 = '1' then
      s1_2 <= latched_value;
    else
      -- s1_2 <= null;			  -- MGC bug workaround
      s1_2 <= X"0000_0000";
      --
    end if;
    if temp_out_en2 = '1' then
      s2_2 <= latched_value;
    else
      -- s2_2 <= null;			  -- MGC bug workaround
      s2_2 <= X"0000_0000";
      --
    end if;
  end process temp_reg;

  ----------------------------------------------------------------

--   iar_reg : reg_2_out
--     port map (d => dest_bus, q1 => s1_3, q2 => s2_3,
--               latch_en => iar_latch_en,
--               out_en1 => iar_out_en1, out_en2 => iar_out_en2);

  iar_reg : process (dest_bus, iar_latch_en, iar_out_en1, iar_out_en2)

    variable latched_value : dlx_word;

  begin
    if iar_latch_en = '1' then
      latched_value := dest_bus;
    end if;
    if iar_out_en1 = '1' then
      s1_3 <= latched_value;
    else
      -- s1_3 <= null;			  -- MGC bug workaround
      s1_3 <= X"0000_0000";
      --
    end if;
    if iar_out_en2 = '1' then
      s2_3 <= latched_value;
    else
      -- s2_3 <= null;			  -- MGC bug workaround
      s2_3 <= X"0000_0000";
      --
    end if;
  end process iar_reg;

  ----------------------------------------------------------------

--   pc_reg : reg_2_1_out
--     port map (d => dest_bus, q1 => s1_4, q2 => s2_4, q3 => pc_to_mem,
--               latch_en => pc_latch_en,
--               out_en1 => pc_out_en1, out_en2 => pc_out_en2);

  pc_reg : process (dest_bus, pc_latch_en, pc_out_en1, pc_out_en2)

    variable latched_value : dlx_word;

  begin
    if pc_latch_en = '1' then
      latched_value := dest_bus;
    end if;
    if pc_out_en1 = '1' then
      s1_4 <= latched_value;
    else
      -- s1_4 <= null;			  -- MGC bug workaround
      s1_4 <= X"0000_0000";
      --
    end if;
    if pc_out_en2 = '1' then
      s2_4 <= latched_value;
    else
      -- s2_4 <= null;			  -- MGC bug workaround
      s2_4 <= X"0000_0000";
      --
    end if;
    pc_to_mem <= latched_value;
  end process pc_reg;

  ----------------------------------------------------------------

--   mar_reg : reg_2_1_out
--     port map (d => dest_bus, q1 => s1_5, q2 => s2_5, q3 => mar_to_mem,
--               latch_en => mar_latch_en,
--               out_en1 => mar_out_en1, out_en2 => mar_out_en2);

  mar_reg : process (dest_bus, mar_latch_en, mar_out_en1, mar_out_en2)

    variable latched_value : dlx_word;

  begin
    if mar_latch_en = '1' then
      latched_value := dest_bus;
    end if;
    if mar_out_en1 = '1' then
      s1_5 <= latched_value;
    else
      -- s1_5 <= null;			  -- MGC bug workaround
      s1_5 <= X"0000_0000";
      --
    end if;
    if mar_out_en2 = '1' then
      s2_5 <= latched_value;
    else
      -- s2_5 <= null;			  -- MGC bug workaround
      s2_5 <= X"0000_0000";
      --
    end if;
    mar_to_mem <= latched_value;
  end process mar_reg;

  ----------------------------------------------------------------

--   mem_addr_mux : mux2
--     port map (i0 => pc_to_mem, i1 => mar_to_mem, y => a,
--               sel => mem_addr_mux_sel);
-- 

  mem_addr_mux : 
    with mem_addr_mux_sel select
      a <=  pc_to_mem when '0',
      	    mar_to_mem when '1';
  ----------------------------------------------------------------

--   mdr_reg : reg_3_out
--     port map (d => mdr_in, q1 => s1_6, q2 => s2_6, q3 => d_write,
--               latch_en => mdr_latch_en,
--               out_en1 => mdr_out_en1, out_en2 => mdr_out_en2,
-- 	      out_en3 => mdr_out_en3);

  mdr_reg : process (mdr_in, mdr_latch_en, mdr_out_en1, mdr_out_en2, mdr_out_en3)

    variable latched_value : dlx_word;

  begin
    if mdr_latch_en = '1' then
      latched_value := mdr_in;
    end if;
    if mdr_out_en1 = '1' then
      s1_6 <= latched_value;
    else
      -- s1_6 <= null;			  -- MGC bug workaround
      s1_6 <= X"0000_0000";
      --
    end if;
    if mdr_out_en2 = '1' then
      s2_6 <= latched_value;
    else
      -- s2_6 <= null;			  -- MGC bug workaround
      s2_6 <= X"0000_0000";
      --
    end if;
    if mdr_out_en3 = '1' then
      d_write <= latched_value;
    else
      -- d_write <= null;			  -- MGC bug workaround
      d_write <= X"0000_0000";
      --
    end if;
  end process mdr_reg;

  ----------------------------------------------------------------

--   mdr_mux : mux2
--     port map (i0 => dest_bus, i1 => d_read, y => mdr_in,
--               sel => mdr_mux_sel);

  mdr_mux :
    with mdr_mux_sel select
      mdr_in <=  dest_bus when '0',
      	      	 d_read when '1';
  ----------------------------------------------------------------

--   instr_reg : ir
--     port map (d => d_read, immed_q1 => s1_7, immed_q2 => s2_7,
--               ir_out => current_instruction,
--               latch_en => ir_latch_en, 
-- 	      immed_sel1 => ir_immed_sel1, immed_sel2 => ir_immed_sel2,
-- 	      immed_unsigned1 => ir_immed_unsigned1, immed_unsigned2 => ir_immed_unsigned2, 
--               immed_en1 => ir_immed_en1, immed_en2 => ir_immed_en2);
  
  instr_reg : process (d_read, ir_latch_en, ir_immed_sel1, ir_immed_sel2, 
      	      	ir_immed_unsigned1, ir_immed_unsigned2, ir_immed_en1, ir_immed_en2)

    variable latched_instr : dlx_word;
    
    use work.bv_arithmetic.bv_zext, work.bv_arithmetic.bv_sext;

  begin
    if ir_latch_en = '1' then
      latched_instr := d_read;
      current_instruction <= latched_instr;
    end if;
    --
    if ir_immed_en1 = '1' then
      if ir_immed_sel1 = immed_size_16 then
      	if ir_immed_unsigned1 = '1' then
	  s1_7 <= bv_zext(latched_instr(16 to 31), 32);
	else
	  s1_7 <= bv_sext(latched_instr(16 to 31), 32);
	end if;
      else -- ir_immed_sel1 = immed_size_26
      	if ir_immed_unsigned1 = '1' then
	  s1_7 <= bv_zext(latched_instr(6 to 31), 32);
	else
	  s1_7 <= bv_sext(latched_instr(6 to 31), 32);
	end if;
      end if;
    else
      -- s1_7 <= null;		  -- MGC bug workaround
      s1_7 <= X"0000_0000";
      --
    end if;
    --
    if ir_immed_en2 = '1' then
      if ir_immed_sel2 = immed_size_16 then
      	if ir_immed_unsigned2 = '1' then
	  s2_7 <= bv_zext(latched_instr(16 to 31), 32);
	else
	  s2_7 <= bv_sext(latched_instr(16 to 31), 32);
	end if;
      else -- ir_immed_sel2 = immed_size_26
      	if ir_immed_unsigned2 = '1' then
	  s2_7 <= bv_zext(latched_instr(6 to 31), 32);
	else
	  s2_7 <= bv_sext(latched_instr(6 to 31), 32);
	end if;
      end if;
    else
      -- s2_7 <= null;		  -- MGC bug workaround
      s2_7 <= X"0000_0000";
      --
    end if;
  end process instr_reg;

  ----------------------------------------------------------------

--   the_controller : controller
--     port map (phi1, phi2, reset, halt, 
--       	      width, write_enable, mem_enable, ifetch, ready, 
--               alu_latch_en, alu_function, alu_zero, alu_negative, alu_overflow,
--               reg_s1_addr, reg_s2_addr, reg_dest_addr, reg_write, 
--               c_latch_en, a_latch_en, a_out_en, b_latch_en, b_out_en, 
--               temp_latch_en, temp_out_en1, temp_out_en2, 
--               iar_latch_en, iar_out_en1, iar_out_en2, 
--               pc_latch_en, pc_out_en1, pc_out_en2, 
--               mar_latch_en, mar_out_en1, mar_out_en2, mem_addr_mux_sel, 
--               mdr_latch_en, mdr_out_en1, mdr_out_en2, 
-- 	      mdr_out_en3, mdr_mux_sel, 
--               ir_latch_en, ir_immed_sel1, ir_immed_sel2,
-- 	      ir_immed_unsigned1, ir_immed_unsigned2, ir_immed_en1, ir_immed_en2,  
--               current_instruction, s1_8, s2_8); 

  the_controller : process

    alias IR_opcode : dlx_opcode is current_instruction(0 to 5);
    alias IR_sp_func : dlx_sp_func is current_instruction(26 to 31);
    alias IR_shamt : dlx_shamt is current_instruction(21 to 25);
    alias IR_fp_func : dlx_fp_func is current_instruction(27 to 31);
    alias IR_rs1 : dlx_reg_addr is current_instruction(6 to 10);
    alias IR_rs2 : dlx_reg_addr is current_instruction(11 to 15);
    alias IR_Itype_rd : dlx_reg_addr is current_instruction(11 to 15);
    alias IR_Rtype_rd : dlx_reg_addr is current_instruction(16 to 20);
    alias IR_immed16 : dlx_immed16 is current_instruction(16 to 31);
    alias IR_immed26 : dlx_immed26 is current_instruction(6 to 31);
    
    variable IR_opcode_num : dlx_opcode_num := bv_to_natural(IR_opcode);
    variable IR_sp_func_num : dlx_sp_func_num := bv_to_natural(IR_sp_func);
    variable IR_fp_func_num : dlx_fp_func_num := bv_to_natural(IR_fp_func);
    
    variable result_of_set_is_1, branch_taken : boolean;
    
    variable L : line;

    procedure bus_instruction_fetch is
    begin
      -- use PC as address
      mem_addr_mux_sel <= '0';
      -- set up memory control signals
      width <= width_word;
      ifetch <= '1';
      mem_enable <= '1';
      -- wait until phi2, then enable IR input
      wait until phi2 = '1';
      ir_latch_en <= '1';
      -- wait until memory is ready at end of phi2
      loop 
        wait until phi2 = '0';
        if reset = '1' then
  	return;
        end if;
        exit when ready = '1';
      end loop;
      -- disable IR input and memory control signals
      ir_latch_en <= '0';
      mem_enable <= '0';
    end bus_instruction_fetch;
    
    procedure bus_data_read(read_width : in mem_width) is
    begin
      -- use MAR as address
      mem_addr_mux_sel <= '1';
      -- set up memory control signals
      width <= read_width;
      ifetch <= '0';
      mem_enable <= '1';
      -- wait until phi2, then enable MDR input
      wait until phi2 = '1';
      mdr_mux_sel <= '1';
      mdr_latch_en <= '1';
      -- wait until memory is ready at end of phi2
      loop 
        wait until phi2 = '0';
        if reset = '1' then
  	return;
        end if;
        exit when ready = '1';
      end loop;
      -- disable MDR input and memory control signals
      mdr_latch_en <= '0';
      mem_enable <= '0';
    end bus_data_read;
    
    procedure bus_data_write(write_width : in mem_width) is
    begin
      -- use MAR as address
      mem_addr_mux_sel <= '1';
      -- enable MDR output
      mdr_out_en3 <= '1';
      -- set up memory control signals
      width <= write_width;
      ifetch <= '0';
      write_enable <= '1';
      mem_enable <= '1';
      -- wait until memory is ready at end of phi2
      loop 
        wait until phi2 = '0';
        if reset = '1' then
  	return;
        end if;
        exit when ready = '1';
      end loop;
      -- disable MDR output and memory control signals
      write_enable <= '0';
      mem_enable <= '0';
      mdr_out_en3 <= '0';
    end bus_data_write;
  
    -- the following arrays give the alu function code during the EX cycle
  
    type alu_function_table_array is array (dlx_opcode_num) of alu_func;
  
    constant alu_function_table : alu_function_table_array
      := (op_num_beqz => alu_sub,
          op_num_bnez => alu_sub,
          op_num_addi => alu_add,
          op_num_addui => alu_addu,
          op_num_subi => alu_sub,
          op_num_subui => alu_subu,
          op_num_andi => alu_and,
          op_num_ori => alu_or,
          op_num_xori => alu_xor,
          op_num_lhi => alu_sll,
          op_num_seqi => alu_sub,
          op_num_snei => alu_sub,
          op_num_slti => alu_sub,
          op_num_sgti => alu_sub,
          op_num_slei => alu_sub,
          op_num_sgei => alu_sub,
          op_num_lb => alu_add,
          op_num_lh => alu_add,
          op_num_lw => alu_add,
          op_num_lbu => alu_add,
          op_num_lhu => alu_add,
          op_num_sb => alu_add,
          op_num_sh => alu_add,
          op_num_sw => alu_add,
          op_num_sequi => alu_subu,
          op_num_sneui => alu_subu,
          op_num_sltui => alu_subu,
          op_num_sgtui => alu_subu,
          op_num_sleui => alu_subu,
          op_num_sgeui => alu_subu,
          others => alu_pass_s1);		  -- for want of anything better
  
    type alu_sp_function_table_array is array (dlx_sp_func_num) of alu_func;
  
    constant alu_sp_function_table : alu_sp_function_table_array
      := (sp_func_num_slli => alu_sll,
          sp_func_num_srli => alu_srl,
          sp_func_num_srai => alu_sra,
          sp_func_num_sll => alu_sll,
          sp_func_num_srl => alu_srl,
          sp_func_num_sra => alu_sra,
          sp_func_num_sequ => alu_subu,
          sp_func_num_sneu => alu_subu,
          sp_func_num_sltu => alu_subu,
          sp_func_num_sgtu => alu_subu,
          sp_func_num_sleu => alu_subu,
          sp_func_num_sgeu => alu_subu,
          sp_func_num_add => alu_add,
          sp_func_num_addu => alu_addu,
          sp_func_num_sub => alu_sub,
          sp_func_num_subu => alu_subu,
          sp_func_num_and => alu_and,
          sp_func_num_or => alu_or,
          sp_func_num_xor => alu_xor,
          sp_func_num_seq => alu_sub,
          sp_func_num_sne => alu_sub,
          sp_func_num_slt => alu_sub,
          sp_func_num_sgt => alu_sub,
          sp_func_num_sle => alu_sub,
          sp_func_num_sge => alu_sub,
          sp_func_num_movi2s => alu_pass_s1,
          sp_func_num_movs2i => alu_pass_s1,
      	  others => alu_pass_s1);		  -- for want of anything better

  begin -- sequencer
    --
    ----------------------------------------------------------------
    --
    -- initialize all control signals
    --
    ----------------------------------------------------------------
    write(L, string'("controller: initializing"));
    writeline(output, L);
    --
    halt <= '0';
    width <= width_word;
    write_enable <= '0';
    mem_enable <= '0';
    ifetch <= '0';
    alu_latch_en <= '0';
    alu_function <= alu_add;
    reg_s1_addr <= B"00000";
    reg_s2_addr <= B"00000";
    reg_dest_addr <= B"00000";
    reg_write <= '0';
    c_latch_en <= '0';
    a_latch_en <= '0'; 
    a_out_en <= '0';
    b_latch_en <= '0';
    b_out_en <= '0';
    temp_latch_en <= '0';
    temp_out_en1 <= '0';
    temp_out_en2 <= '0';
    iar_latch_en <= '0';
    iar_out_en1 <= '0';
    iar_out_en2 <= '0';
    pc_latch_en <= '0';
    pc_out_en1 <= '0';
    pc_out_en2 <= '0';
    mar_latch_en <= '0';
    mar_out_en1 <= '0';
    mar_out_en2 <= '0';
    mem_addr_mux_sel <= '0';
    mdr_latch_en <= '0';
    mdr_out_en1 <= '0';
    mdr_out_en2 <= '0';
    mdr_out_en3 <= '0';
    mdr_mux_sel <= '0';
    ir_latch_en <= '0';
    ir_immed_sel1 <= immed_size_16;
    ir_immed_sel2 <= immed_size_16;
    ir_immed_unsigned1 <= '0';
    ir_immed_unsigned2 <= '0';
    ir_immed_en1 <= '0';
    ir_immed_en2 <= '0';
    -- const <= null;
    s1_8 <= X"0000_0000";
    s2_8 <= X"0000_0000";
    --
    wait until phi2 = '0' and reset = '0';
    --
    ----------------------------------------------------------------
    --
    -- control loop
    --
    ----------------------------------------------------------------
    loop
      ----------------------------------------------------------------
      --
      -- fetch next instruction (IF)
      --
      ----------------------------------------------------------------
      wait until phi1 = '1';
      write(L, string'("controller: instruction fetch"));
      writeline(output, L);
      --
      bus_instruction_fetch;
      ----------------------------------------------------------------
      --
      -- instruction decode, source register read, and PC increment (ID)
      --
      ----------------------------------------------------------------
      wait until phi1 = '1';
      write(L, string'("controller: decode, reg-read and PC incr"));
      writeline(output, L);
      --
      IR_opcode_num := bv_to_natural(IR_opcode);
      IR_sp_func_num := bv_to_natural(IR_sp_func);
      IR_fp_func_num := bv_to_natural(IR_fp_func);
      --
      reg_s1_addr <= IR_rs1;
      reg_s2_addr <= IR_rs2;
      a_latch_en <= '1';
      b_latch_en <= '1';
      --
      pc_out_en1 <= '1';
      s2_8 <= X"0000_0004";
      alu_latch_en <= '1';
      alu_function <= alu_addu;
      --
      wait until phi1 = '0';
      alu_latch_en <= '0';
      pc_out_en1 <= '0';
      -- const <= null;
      s2_8 <= X"0000_0000";
      --
      wait until phi2 = '1';
      pc_latch_en <= '1';
      --
      wait until phi2 = '0';
      a_latch_en <= '0';
      b_latch_en <= '0';
      pc_latch_en <= '0';
      ----------------------------------------------------------------
      --
      -- execute instruction, or calculate effective address (EX)
      --
      ----------------------------------------------------------------
      wait until phi1 = '1';
      write(L, string'("controller: execute"));
      writeline(output, L);
      --
      case IR_opcode_num is
      	when op_num_special => 
      	  case IR_sp_func_num is
      	    when sp_func_num_slli => 
	      assert false
	      	report "SLLI instruction not implemented" severity warning;
      	    when sp_func_num_srli =>
	      assert false
	      	report "SLRI instruction not implemented" severity warning;
      	    when sp_func_num_srai => 
      	      assert false
	      	report "SRAI instruction not implemented" severity warning;
      	    when sp_func_num_sequ =>
	      assert false
	      	report "SEQU instruction not implemented" severity warning;
      	    when sp_func_num_sneu => 
      	      assert false
	      	report "SNEU instruction not implemented" severity warning;
      	    when sp_func_num_sltu => 
      	      assert false
	      	report "SLTU instruction not implemented" severity warning;
      	    when sp_func_num_sgtu => 
      	      assert false
	      	report "SGTU instruction not implemented" severity warning;
      	    when sp_func_num_sleu => 
      	      assert false
	      	report "SLEU instruction not implemented" severity warning;
      	    when sp_func_num_sgeu => 
      	      assert false
	      	report "SGEU instruction not implemented" severity warning;
      	    when sp_func_num_mult => 
	      assert false
	      	report "MULT instruction not implemented" severity warning;
      	    when sp_func_num_multu => 
      	      assert false
	      	report "MULTU instruction not implemented" severity warning;
      	    when sp_func_num_div => 
      	      assert false
	      	report "DIV instruction not implemented" severity warning;
      	    when sp_func_num_divu => 
      	      assert false
	      	report "DIVU instruction not implemented" severity warning;
      	    when sp_func_num_add | sp_func_num_addu |
  	         sp_func_num_sub | sp_func_num_subu |
      	         sp_func_num_and | sp_func_num_or | sp_func_num_xor |
      	         sp_func_num_sll | sp_func_num_srl | sp_func_num_sra => 
	      a_out_en <= '1';
      	      b_out_en <= '1';
      	      alu_latch_en <= '1';
      	      alu_function <= alu_sp_function_table(IR_sp_func_num);
      	      --
      	      wait until phi1 = '0';
      	      alu_latch_en <= '0';
      	      a_out_en <= '0';
      	      b_out_en <= '0';
      	      --
      	      wait until phi2 = '1';
      	      c_latch_en <= '1';
      	      --
      	      wait until phi2 = '0';
      	      c_latch_en <= '0';
      	    when sp_func_num_seq | sp_func_num_sne | 
        	sp_func_num_slt | sp_func_num_sgt |
                sp_func_num_sle | sp_func_num_sge => 
      	      a_out_en <= '1';
      	      b_out_en <= '1';
      	      alu_latch_en <= '1';
      	      alu_function <= alu_sp_function_table(IR_sp_func_num);
      	      --
      	      wait until phi1 = '0';
      	      alu_latch_en <= '0';
      	      a_out_en <= '0';
      	      b_out_en <= '0';
      	      --
      	      wait until phi2 = '0';
	      case IR_sp_func_num is
      	        when sp_func_num_seq => 
		  result_of_set_is_1 := alu_zero = '1';
       	        when sp_func_num_sne =>
		  result_of_set_is_1 := alu_zero /= '1';
        	when sp_func_num_slt =>
		  result_of_set_is_1 := alu_negative = '1';
      	        when sp_func_num_sgt => 
      	      	  result_of_set_is_1 := alu_negative /= '1' and alu_zero /= '1';
      	        when sp_func_num_sle => 
      	      	  result_of_set_is_1 := alu_negative = '1' or alu_zero = '1';
      	        when sp_func_num_sge => 
      	      	  result_of_set_is_1 := alu_negative /= '1';
	        when others =>
		  null;
	      end case;
	      --
	      wait until phi1 = '1';
	      if result_of_set_is_1 then
	      	s2_8 <= X"0000_0001";
	      else
	        s2_8 <= X"0000_0000";
	      end if;
	      alu_latch_en <= '1';
      	      alu_function <= alu_pass_s2;
      	      --
      	      wait until phi1 = '0';
      	      alu_latch_en <= '0';
      	      -- const <= null;
	      s2_8 <= X"0000_0000";
      	       --
	      wait until phi2 = '1';
	      c_latch_en <= '1';
	      --
      	      wait until phi2 = '0';
	      c_latch_en <= '0';
       	    when sp_func_num_movi2s => 
	      assert false
	      	report "MOVI2S instruction not implemented" severity warning;
      	    when sp_func_num_movs2i => 
      	      assert false
	      	report "MOVS2I instruction not implemented" severity warning;
      	    when sp_func_num_movf => 
      	      assert false
	      	report "MOVF instruction not implemented" severity warning;
      	    when sp_func_num_movd => 
      	      assert false
	      	report "MOVD instruction not implemented" severity warning;
      	    when sp_func_num_movfp2i => 
      	      assert false
	      	report "MOVFP2I instruction not implemented" severity warning;
      	    when sp_func_num_movi2fp => 
      	      assert false
	      	report "MOVI2FP instruction not implemented" severity warning;
      	    when others =>
	      assert false
	      	report "undefined special instruction function" severity error;
    	  end case;  
      	when op_num_fparith => 
      	  case IR_fp_func_num is
      	    when fp_func_num_addf | fp_func_num_subf | fp_func_num_multf | fp_func_num_divf | 
      	      fp_func_num_addd | fp_func_num_subd | fp_func_num_multd | fp_func_num_divd | 
      	      fp_func_num_cvtf2d | fp_func_num_cvtf2i | fp_func_num_cvtd2f | 
      	      fp_func_num_cvtd2i | fp_func_num_cvti2f | fp_func_num_cvti2d | 
      	      fp_func_num_eqf | fp_func_num_nef | fp_func_num_ltf | fp_func_num_gtf | 
      	      fp_func_num_lef | fp_func_num_gef | fp_func_num_eqd | fp_func_num_ned | 
      	      fp_func_num_ltd | fp_func_num_gtd | fp_func_num_led | fp_func_num_ged => 
      	      assert false
	      	report "floating point instructions not implemented" severity warning;
      	    when others =>
	      assert false
	      	report "undefined floating point instruction function" severity error;
	  end case;
      	when op_num_j  | op_num_jr => 
      	  null;  -- PC updated during MEM
      	when op_num_jal | op_num_jalr => 
	  pc_out_en1 <= '1';
	  alu_latch_en <= '1';
	  alu_function <= alu_pass_s1;
	  --
	  wait until phi1 = '0';
	  alu_latch_en <= '0';
	  pc_out_en1 <= '0';
	  --
	  wait until phi2 = '1';
	  c_latch_en <= '1';
	  --
	  wait until phi2 = '0';
	  c_latch_en <= '0';
      	  -- PC updated during MEM, link reg written during WB
      	when op_num_beqz | op_num_bnez => 
	  a_out_en <= '1';
	  s2_8 <= X"0000_0000";
	  alu_latch_en <= '1';
	  alu_function <= alu_function_table(IR_opcode_num);
	  --
	  wait until phi1 = '0';
	  alu_latch_en <= '0';
	  a_out_en <= '0';
	  -- const <= null;
	  s2_8 <= X"0000_0000";
	  --
	  wait until phi2 = '0';
	  case IR_opcode_num is
    	    when op_num_beqz => 
	      branch_taken := alu_zero = '1';
      	    when op_num_bnez => 
	      branch_taken := alu_zero /= '1';
      	    when others =>
	      null;
      	  end case;
	  -- if branch_taken, PC updated during MEM
      	when op_num_bfpt => 
      	  assert false
	    report "BFPT instruction not implemented" severity warning;
      	when op_num_bfpf => 
      	  assert false
	    report "BFPF instruction not implemented" severity warning;
      	when op_num_addi | op_num_subi =>
	  a_out_en <= '1';
      	  ir_immed_sel2 <= immed_size_16;
	  ir_immed_unsigned2 <= '0';
	  ir_immed_en2 <= '1';
      	  alu_latch_en <= '1';
      	  alu_function <= alu_function_table(IR_opcode_num);
      	  --
      	  wait until phi1 = '0';
      	  alu_latch_en <= '0';
      	  a_out_en <= '0';
      	  ir_immed_en2 <= '0';
      	  --
      	  wait until phi2 = '1';
      	  c_latch_en <= '1';
      	  --
      	  wait until phi2 = '0';
      	  c_latch_en <= '0';
      	when op_num_addui | op_num_subui | 
       	    op_num_andi | op_num_ori | op_num_xori => 
	  a_out_en <= '1';
      	  ir_immed_sel2 <= immed_size_16;
	  ir_immed_unsigned2 <= '1';
	  ir_immed_en2 <= '1';
      	  alu_latch_en <= '1';
      	  alu_function <= alu_function_table(IR_opcode_num);
      	  --
      	  wait until phi1 = '0';
      	  alu_latch_en <= '0';
      	  a_out_en <= '0';
      	  ir_immed_en2 <= '0';
      	  --
      	  wait until phi2 = '1';
      	  c_latch_en <= '1';
      	  --
      	  wait until phi2 = '0';
      	  c_latch_en <= '0';
      	when op_num_lhi => 
      	  ir_immed_sel1 <= immed_size_16;
	  ir_immed_unsigned1 <= '1';
	  ir_immed_en1 <= '1';
	  s2_8 <= X"0000_0010";	  -- shift by 16 bits
      	  alu_latch_en <= '1';
      	  alu_function <= alu_function_table(IR_opcode_num);
      	  --
      	  wait until phi1 = '0';
      	  alu_latch_en <= '0';
      	  ir_immed_en1 <= '0';
	  -- const <= null;
	  s2_8 <= X"0000_0000";
      	  --
      	  wait until phi2 = '1';
      	  c_latch_en <= '1';
      	  --
      	  wait until phi2 = '0';
      	  c_latch_en <= '0';
      	when op_num_rfe => 
      	  assert false
	    report "RFE instruction not implemented" severity warning;
      	when op_num_trap =>
      	  assert false
	    report "TRAP instruction encountered, execution halted"
	    severity note;
      	  halt <= '1';
	  wait until reset = '1';
	  exit;
      	when op_num_seqi | op_num_snei | op_num_slti |
       	    op_num_sgti | op_num_slei | op_num_sgei => 
      	  a_out_en <= '1';
      	  ir_immed_sel2 <= immed_size_16;
	  ir_immed_unsigned2 <= '0';
	  ir_immed_en2 <= '1';
      	  alu_latch_en <= '1';
      	  alu_function <= alu_function_table(IR_opcode_num);
      	  --
      	  wait until phi1 = '0';
      	  alu_latch_en <= '0';
      	  a_out_en <= '0';
      	  ir_immed_en2 <= '0';
      	  --
      	  wait until phi2 = '0';
	  case IR_opcode_num is
      	    when op_num_seqi => 
	      result_of_set_is_1 := alu_zero = '1';
       	    when op_num_snei =>
	      result_of_set_is_1 := alu_zero /= '1';
            when op_num_slti =>
	      result_of_set_is_1 := alu_negative = '1';
      	    when op_num_sgti => 
      	  	  result_of_set_is_1 := alu_negative /= '1' and alu_zero /= '1';
      	    when op_num_slei => 
      	  	  result_of_set_is_1 := alu_negative = '1' or alu_zero = '1';
      	    when op_num_sgei => 
      	  	  result_of_set_is_1 := alu_negative /= '1';
	    when others =>
	      null;
	  end case;
	  --
	  wait until phi1 = '1';
	  if result_of_set_is_1 then
	    s2_8 <= X"0000_0001";
	  else
	    s2_8 <= X"0000_0000";
	  end if;
	  alu_latch_en <= '1';
      	  alu_function <= alu_pass_s2;
      	  --
      	  wait until phi1 = '0';
      	  alu_latch_en <= '0';
      	  -- const <= null;
	  s2_8 <= X"0000_0000";
      	   --
	  wait until phi2 = '1';
	  c_latch_en <= '1';
	  --
      	  wait until phi2 = '0';
	  c_latch_en <= '0';
        when op_num_lb =>
	  assert false
	    report "LB instruction not implemented" severity warning;
        when op_num_lh =>
	  assert false
	    report "LH instruction not implemented" severity warning;
        when op_num_lw | op_num_sw => 
      	  a_out_en <= '1';
	  ir_immed_sel2 <= immed_size_16;
	  ir_immed_unsigned2 <= '0';
	  ir_immed_en2 <= '1';
	  alu_function <= alu_function_table(IR_opcode_num);
	  alu_latch_en <= '1';
	  --
	  wait until phi1 = '0';
	  alu_latch_en <= '0';
	  a_out_en <= '0';
	  ir_immed_en2 <= '0';
	  --
	  wait until phi2 = '1';
	  mar_latch_en <= '1';
	  --
	  wait until phi2 = '0';
	  mar_latch_en <= '0';
        when op_num_lbu =>
	  assert false
	    report "LBU instruction not implemented" severity warning;
        when op_num_lhu =>
	  assert false
	    report "LHU instruction not implemented" severity warning;
        when op_num_sb => 
	  assert false
	    report "SB instruction not implemented" severity warning;
        when op_num_sh =>
	  assert false
	    report "SH instruction not implemented" severity warning;
        when op_num_lf => 
	  assert false
	    report "LF instruction not implemented" severity warning;
      	when op_num_ld => 
	  assert false
	    report "LD instruction not implemented" severity warning;
        when op_num_sf => 
	  assert false
	    report "SF instruction not implemented" severity warning;
      	when op_num_sd => 
	  assert false
	    report "SD instruction not implemented" severity warning;
      	when op_num_sequi => 
	  assert false
	    report "SEQUI instruction not implemented" severity warning;
      	when op_num_sneui => 
	  assert false
	    report "SNEUI instruction not implemented" severity warning;
      	when op_num_sltui => 
	  assert false
	    report "SLTUI instruction not implemented" severity warning;
      	when op_num_sgtui => 
	  assert false
	    report "SGTUI instruction not implemented" severity warning;
      	when op_num_sleui => 
	  assert false
	    report "SLEUI instruction not implemented" severity warning;
      	when op_num_sgeui => 
      	  assert false
	    report "SGEUI instruction not implemented" severity warning;
      	when others =>
	  assert false
	    report "undefined instruction" severity error;
      end case;
      ----------------------------------------------------------------
      --
      -- memory operand access, or branch completion (MEM)
      --
      ----------------------------------------------------------------
      wait until phi1 = '1';
      write(L, string'("controller: memory access or branch completion"));
      writeline(output, L);
      --
      case IR_opcode_num is
      	when op_num_special => 
      	  null;
      	when op_num_fparith => 
          null;
      	when op_num_j  | op_num_jal => 
 	  pc_out_en1 <= '1';
	  ir_immed_sel2 <= immed_size_26;
	  ir_immed_unsigned2 <= '0';
	  ir_immed_en2 <= '1';
	  alu_latch_en <= '1';
	  alu_function <= alu_add;
	  --
	  wait until phi1 = '0';
	  alu_latch_en <= '0';
	  pc_out_en1 <= '0';
	  ir_immed_en2 <= '0';
	  --
	  wait until phi2 = '1';
	  pc_latch_en <= '1';
	  --
	  wait until phi2 = '0';
	  pc_latch_en <= '0';
      	when op_num_jr | op_num_jalr => 
 	  a_out_en <= '1';
	  alu_latch_en <= '1';
	  alu_function <= alu_pass_s1;
	  --
	  wait until phi1 = '0';
	  alu_latch_en <= '0';
	  a_out_en <= '0';
	  --
	  wait until phi2 = '1';
	  pc_latch_en <= '1';
	  --
	  wait until phi2 = '0';
	  pc_latch_en <= '0';
      	when op_num_beqz | op_num_bnez => 
      	  if branch_taken then
 	    pc_out_en1 <= '1';
	    ir_immed_sel2 <= immed_size_16;
	    ir_immed_unsigned2 <= '0';
	    ir_immed_en2 <= '1';
	    alu_latch_en <= '1';
	    alu_function <= alu_add;
	    --
	    wait until phi1 = '0';
	    alu_latch_en <= '0';
	    pc_out_en1 <= '0';
	    ir_immed_en2 <= '0';
	    --
	    wait until phi2 = '1';
	    pc_latch_en <= '1';
	    --
	    wait until phi2 = '0';
	    pc_latch_en <= '0';
	  end if;
        when op_num_lw =>
	  bus_data_read(width_word);
      	  exit when reset = '1';
	  --
	  wait until phi1 = '1';
	  mdr_out_en1 <= '1';
	  alu_function <= alu_pass_s1;
	  alu_latch_en <= '1';
	  --
	  wait until phi1 = '0';
	  mdr_out_en1 <= '0';
	  alu_latch_en <= '0';
	  --
	  wait until phi2 = '1';
	  c_latch_en <= '1';
	  --
	  wait until phi2 = '0';
	  c_latch_en <= '0';
        when op_num_sw => 
	  b_out_en <= '1';
	  alu_function <= alu_pass_s2;
	  alu_latch_en <= '1';
	  --
	  wait until phi1 = '0';
	  b_out_en <= '0';
	  alu_latch_en <= '0';
	  --
	  wait until phi2 = '1';
	  mdr_mux_sel <= '0';
	  mdr_latch_en <= '1';
	  --
	  wait until phi2 = '0';
	  mdr_latch_en <= '0';
      	  --
	  wait until phi1 = '1';
	  bus_data_write(width_word);
	  exit when reset = '1';
      	when others =>
      	  null;
      end case;
      ----------------------------------------------------------------
      --
      -- register write back (WB)
      --
      ----------------------------------------------------------------
      wait until phi1 = '1';
      write(L, string'("controller: write-back"));
      writeline(output, L);
      --
      case IR_opcode_num is
      	when op_num_special => 
      	  case IR_sp_func_num is
      	    when sp_func_num_add | sp_func_num_addu |
  	        sp_func_num_sub | sp_func_num_subu |
      	        sp_func_num_and | sp_func_num_or | sp_func_num_xor |
      	        sp_func_num_sll | sp_func_num_srl | sp_func_num_sra |
      	        sp_func_num_seq | sp_func_num_sne | 
        	sp_func_num_slt | sp_func_num_sgt |
                sp_func_num_sle | sp_func_num_sge => 
	      reg_dest_addr <= IR_Rtype_rd;
	      reg_write <= '1';
	      --
	      wait until phi2 = '0';
	      reg_write <= '0';
      	    when others =>
      	      null;
	  end case;
      	when op_num_fparith => 
	  null;
      	when op_num_jal | op_num_jalr => 
      	  reg_dest_addr <= natural_to_bv(link_reg, 5);
	  reg_write <= '1';
	  --
	  wait until phi2 = '0';
	  reg_write <= '0';
      	when op_num_addi | op_num_subi |
      	    op_num_addui | op_num_subui | 
       	    op_num_andi | op_num_ori | op_num_xori |
      	    op_num_lhi |
      	    op_num_seqi | op_num_snei | op_num_slti |
       	    op_num_sgti | op_num_slei | op_num_sgei |
            op_num_lw =>
	  reg_dest_addr <= IR_Itype_rd;
	  reg_write <= '1';
	  --
	  wait until phi2 = '0';
	  reg_write <= '0';
      	when others =>
      	  null;
      end case;
      --
    end loop;
    ----------------------------------------------------------------
    --
    -- loop exited on reset
    --
    ----------------------------------------------------------------
    assert reset = '1'
  	      	 report "Internal error: reset code reached with reset = '0'"
	   severity failure;
    --
    -- start again
    --
  end process the_controller;

  ----------------------------------------------------------------

--   bus_resolver_1 : dlx_bus_resolver
--     port map (i1 => s1_1, i2 => s1_2, i3 => s1_3, i4 => s1_4,
--       	      i5 => s1_5, i6 => s1_6, i7 => s1_7, i8 => s1_8,
--       	      z => s1_bus);

  bus_resolver_1 : process (s1_1, s1_2, s1_3, s1_4, s1_5, s1_6, s1_7, s1_8)
  begin
    s1_bus <= s1_1 or s1_2 or s1_3 or s1_4 or s1_5 or s1_6 or s1_7 or s1_8;
  end process;
  
  ----------------------------------------------------------------
	   
--   bus_resolver_2 : dlx_bus_resolver
--     port map (i1 => s2_1, i2 => s2_2, i3 => s2_3, i4 => s2_4,
--       	      i5 => s2_5, i6 => s2_6, i7 => s2_7, i8 => s2_8,
--       	      z => s2_bus);

  bus_resolver_2 : process (s2_1, s2_2, s2_3, s2_4, s2_5, s2_6, s2_7, s2_8)
  begin
    s2_bus <= s2_1 or s2_2 or s2_3 or s2_4 or s2_5 or s2_6 or s2_7 or s2_8;
  end process;
  
  ----------------------------------------------------------------

  s1_monitor : process (s1_bus)
    variable L : line;
  begin
    write(L, string'("s1_monitor: "));
    write_hex(L, s1_bus);
    writeline(output, L);
  end process s1_monitor;

  ----------------------------------------------------------------

  s2_monitor : process (s2_bus)
    variable L : line;
  begin
    write(L, string'("s2_monitor: "));
    write_hex(L, s2_bus);
    writeline(output, L);
  end process s2_monitor;

  ----------------------------------------------------------------

  dest_monitor : process (dest_bus)
    variable L : line;
  begin
    write(L, string'("dest_monitor: "));
    write_hex(L, dest_bus);
    writeline(output, L);
  end process dest_monitor;

  ----------------------------------------------------------------

end bench;

<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>