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;