diff --git a/common.vhdl b/common.vhdl index cc49e8f..4f8191e 100644 --- a/common.vhdl +++ b/common.vhdl @@ -115,28 +115,29 @@ package common is -- Some SPRs are stored in a pair of small RAMs in execute1 -- Even half: - subtype ramspr_index is natural range 0 to 7; - constant RAMSPR_SRR0 : ramspr_index := 0; - constant RAMSPR_HSRR0 : ramspr_index := 1; - constant RAMSPR_SPRG0 : ramspr_index := 2; - constant RAMSPR_SPRG2 : ramspr_index := 3; - constant RAMSPR_HSPRG0 : ramspr_index := 4; - constant RAMSPR_LR : ramspr_index := 5; -- must equal RAMSPR_CTR - constant RAMSPR_TAR : ramspr_index := 6; + subtype ramspr_index_range is natural range 0 to 7; + subtype ramspr_index is unsigned(2 downto 0); + constant RAMSPR_SRR0 : ramspr_index := to_unsigned(0,3); + constant RAMSPR_HSRR0 : ramspr_index := to_unsigned(1,3); + constant RAMSPR_SPRG0 : ramspr_index := to_unsigned(2,3); + constant RAMSPR_SPRG2 : ramspr_index := to_unsigned(3,3); + constant RAMSPR_HSPRG0 : ramspr_index := to_unsigned(4,3); + constant RAMSPR_LR : ramspr_index := to_unsigned(5,3); -- must equal RAMSPR_CTR + constant RAMSPR_TAR : ramspr_index := to_unsigned(6,3); -- Odd half: - constant RAMSPR_SRR1 : ramspr_index := 0; - constant RAMSPR_HSRR1 : ramspr_index := 1; - constant RAMSPR_SPRG1 : ramspr_index := 2; - constant RAMSPR_SPRG3 : ramspr_index := 3; - constant RAMSPR_HSPRG1 : ramspr_index := 4; - constant RAMSPR_CTR : ramspr_index := 5; -- must equal RAMSPR_LR + constant RAMSPR_SRR1 : ramspr_index := to_unsigned(0,3); + constant RAMSPR_HSRR1 : ramspr_index := to_unsigned(1,3); + constant RAMSPR_SPRG1 : ramspr_index := to_unsigned(2,3); + constant RAMSPR_SPRG3 : ramspr_index := to_unsigned(3,3); + constant RAMSPR_HSPRG1 : ramspr_index := to_unsigned(4,3); + constant RAMSPR_CTR : ramspr_index := to_unsigned(5,3); -- must equal RAMSPR_LR type ram_spr_info is record index : ramspr_index; isodd : std_ulogic; valid : std_ulogic; end record; - constant ram_spr_info_init: ram_spr_info := (index => 0, others => '0'); + constant ram_spr_info_init: ram_spr_info := (index => to_unsigned(0,3), others => '0'); subtype spr_selector is std_ulogic_vector(2 downto 0); type spr_id is record @@ -366,8 +367,8 @@ package common is result_sel => "000", sub_select => "000", repeat => '0', second => '0', spr_select => spr_id_init, spr_is_ram => '0', - ramspr_even_rdaddr => 0, ramspr_odd_rdaddr => 0, ramspr_rd_odd => '0', - ramspr_wraddr => 0, ramspr_write_even => '0', ramspr_write_odd => '0', + ramspr_even_rdaddr => (others => '0'), ramspr_odd_rdaddr => (others => '0'), ramspr_rd_odd => '0', + ramspr_wraddr => (others => '0'), ramspr_write_even => '0', ramspr_write_odd => '0', dbg_spr_access => '0', dec_ctr => '0', others => (others => '0')); diff --git a/core_debug.vhdl b/core_debug.vhdl index c060f74..c9c3f40 100644 --- a/core_debug.vhdl +++ b/core_debug.vhdl @@ -273,7 +273,7 @@ begin valid := '1'; sel := "000"; isram := '1'; - raddr := 0; + raddr := (others => '0'); odd := '0'; case gspr_index(4 downto 0) is when 5x"00" => @@ -304,7 +304,7 @@ begin when others => valid := '0'; end case; - dbg_spr_addr <= isram & sel & std_ulogic_vector(to_unsigned(raddr, 3)) & odd; + dbg_spr_addr <= isram & sel & std_ulogic_vector(raddr) & odd; spr_index_valid <= valid; end if; end process; diff --git a/decode1.vhdl b/decode1.vhdl index de9b836..b2c6059 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -36,6 +36,8 @@ architecture behaviour of decode1 is constant illegal_inst : decode_rom_t := (NONE, NONE, OP_ILLEGAL, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE); + constant x_inst : decode_rom_t := + (NONE, NONE, OP_ILLEGAL, NONE, NONE, NONE, NONE, 'X', 'X', 'X', 'X', ZERO, 'X', NONE, 'X', 'X', 'X', 'X', 'X', 'X', NONE, 'X', 'X', NONE); -- If we have an FPU, then it is used for integer divisions, -- otherwise a dedicated divider in the ALU is used. @@ -530,7 +532,7 @@ architecture behaviour of decode1 is function decode_ram_spr(sprn : spr_num_t) return ram_spr_info is variable ret : ram_spr_info; begin - ret := (index => 0, isodd => '0', valid => '1'); + ret := (index => (others => '0'), isodd => '0', valid => '1'); case sprn is when SPR_LR => ret.index := RAMSPR_LR; @@ -664,14 +666,23 @@ begin br_offset := (others => '0'); majorop := unsigned(f_in.insn(31 downto 26)); - v.decode := major_decode_rom_array(to_integer(majorop)); - - sprn := decode_spr_num(f_in.insn); - v.spr_info := map_spr(sprn); - v.ram_spr := decode_ram_spr(sprn); + if is_X(majorop) then + v.decode := x_inst; + else + v.decode := major_decode_rom_array(to_integer(majorop)); + end if; - case to_integer(unsigned(majorop)) is - when 4 => + if is_X(f_in.insn) then + v.spr_info := (sel => "XXX", others => 'X'); + v.ram_spr := (index => (others => 'X'), others => 'X'); + else + sprn := decode_spr_num(f_in.insn); + v.spr_info := map_spr(sprn); + v.ram_spr := decode_ram_spr(sprn); + end if; + + case unsigned(majorop) is + when "000100" => -- 4 -- major opcode 4, mostly VMX/VSX stuff but also some integer ops (madd*) minor4op := f_in.insn(5 downto 0) & f_in.insn(10 downto 6); vi.override := not decode_op_4_valid(to_integer(unsigned(minor4op))); @@ -679,13 +690,17 @@ begin in3rc := '1'; may_read_rb := '1'; - when 23 => + when "010111" => -- 23 -- rlwnm[.] may_read_rb := '1'; - when 31 => + when "011111" => -- 31 -- major opcode 31, lots of things - v.decode := decode_op_31_array(to_integer(unsigned(f_in.insn(10 downto 1)))); + if is_X(f_in.insn) then + v.decode := x_inst; + else + v.decode := decode_op_31_array(to_integer(unsigned(f_in.insn(10 downto 1)))); + end if; may_read_rb := '1'; if std_match(f_in.insn(10 downto 1), "01-1010011") then @@ -705,28 +720,43 @@ begin end if; when others => end case; + -- FIXME: This is a bit fragile doing this here but sprn depends + -- on f_in.insn + if is_X(f_in.insn) then + vi.override_decode.unit := NONE; + vi.override_unit := 'X'; + vi.force_single := 'X'; + end if; end if; if HAS_FPU and std_match(f_in.insn(10 downto 1), "1----10111") then -- lower half of column 23 has FP loads and stores fprs := '1'; end if; - when 16 => + when "010000" => -- 16 -- Predict backward branches as taken, forward as untaken v.br_pred := f_in.insn(15); br_offset := resize(signed(f_in.insn(15 downto 2)), 24); - when 18 => + when "010010" => -- 18 -- Unconditional branches are always taken v.br_pred := '1'; br_offset := signed(f_in.insn(25 downto 2)); - when 19 => - vi.override := not decode_op_19_valid(to_integer(unsigned(f_in.insn(5 downto 1) & f_in.insn(10 downto 6)))); + when "010011" => -- 19 + if is_X(f_in.insn) then + vi.override := 'X'; + else + vi.override := not decode_op_19_valid(to_integer(unsigned(f_in.insn(5 downto 1) & f_in.insn(10 downto 6)))); + end if; op_19_bits := f_in.insn(5) & f_in.insn(3) & f_in.insn(2); - v.decode := decode_op_19_array(to_integer(unsigned(op_19_bits))); + if is_X(op_19_bits) then + v.decode := x_inst; + else + v.decode := decode_op_19_array(to_integer(unsigned(op_19_bits))); + end if; - when 24 => + when "011000" => -- 24 -- ori, special-case the standard NOP if std_match(f_in.insn, "01100000000000000000000000000000") then report "PPC_nop"; @@ -734,23 +764,35 @@ begin vi.override_decode := nop_instr; end if; - when 30 => - v.decode := decode_op_30_array(to_integer(unsigned(f_in.insn(4 downto 1)))); + when "011110" => -- 30 + if is_X(f_in.insn) then + v.decode := x_inst; + else + v.decode := decode_op_30_array(to_integer(unsigned(f_in.insn(4 downto 1)))); + end if; may_read_rb := f_in.insn(4); - when 52 | 53 | 54 | 55 => + when "110100" | "110101" | "110110" | "110111" => -- 52, 53, 54, 55 -- stfd[u] and stfs[u] if HAS_FPU then fprs := '1'; end if; - when 58 => - v.decode := decode_op_58_array(to_integer(unsigned(f_in.insn(1 downto 0)))); + when "111010" => -- 58 + if is_X(f_in.insn) then + v.decode := x_inst; + else + v.decode := decode_op_58_array(to_integer(unsigned(f_in.insn(1 downto 0)))); + end if; - when 59 => + when "111011" => -- 59 if HAS_FPU then -- floating point operations, mostly single-precision - v.decode := decode_op_59_array(to_integer(unsigned(f_in.insn(5 downto 1)))); + if is_X(f_in.insn) then + v.decode := x_inst; + else + v.decode := decode_op_59_array(to_integer(unsigned(f_in.insn(5 downto 1)))); + end if; if f_in.insn(5) = '0' and not std_match(f_in.insn(10 downto 1), "11-1001110") then vi.override := '1'; end if; @@ -760,13 +802,19 @@ begin may_read_rb := '1'; end if; - when 62 => - v.decode := decode_op_62_array(to_integer(unsigned(f_in.insn(1 downto 0)))); + when "111110" => -- 62 + if is_X(f_in.insn) then + v.decode := x_inst; + else + v.decode := decode_op_62_array(to_integer(unsigned(f_in.insn(1 downto 0)))); + end if; - when 63 => + when "111111" => -- 63 if HAS_FPU then -- floating point operations, general and double-precision - if f_in.insn(5) = '0' then + if is_X(f_in.insn) then + v.decode := x_inst; + elsif f_in.insn(5) = '0' then v.decode := decode_op_63l_array(to_integer(unsigned(f_in.insn(4 downto 1) & f_in.insn(10 downto 6)))); else v.decode := decode_op_63h_array(to_integer(unsigned(f_in.insn(4 downto 1)))); diff --git a/decode2.vhdl b/decode2.vhdl index e24ebb5..1392aae 100644 --- a/decode2.vhdl +++ b/decode2.vhdl @@ -671,8 +671,8 @@ begin v.e.dbg_spr_access := dbg_spr_req and not v.read_rspr; if v.e.dbg_spr_access = '1' then - v.e.ramspr_even_rdaddr := to_integer(unsigned(dbg_spr_addr(3 downto 1))); - v.e.ramspr_odd_rdaddr := to_integer(unsigned(dbg_spr_addr(3 downto 1))); + v.e.ramspr_even_rdaddr := unsigned(dbg_spr_addr(3 downto 1)); + v.e.ramspr_odd_rdaddr := unsigned(dbg_spr_addr(3 downto 1)); v.e.ramspr_rd_odd := dbg_spr_addr(0); end if; diff --git a/execute1.vhdl b/execute1.vhdl index 20efef6..d77b16f 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -147,7 +147,7 @@ architecture behaviour of execute1 is taken_branch_event => '0', br_mispredict => '0', msr => 64x"0", xerc => xerc_init, xerc_valid => '0', - ramspr_wraddr => 0, ramspr_odd_data => 64x"0"); + ramspr_wraddr => (others => '0'), ramspr_odd_data => 64x"0"); type reg_stage2_type is record e : Execute1ToWritebackType; @@ -221,7 +221,7 @@ architecture behaviour of execute1 is signal irq_valid_log : std_ulogic; -- SPR-related signals - type ramspr_half_t is array(ramspr_index) of std_ulogic_vector(63 downto 0); + type ramspr_half_t is array(ramspr_index_range) of std_ulogic_vector(63 downto 0); signal even_sprs : ramspr_half_t := (others => (others => '0')); signal odd_sprs : ramspr_half_t := (others => (others => '0')); signal ramspr_even : std_ulogic_vector(63 downto 0); @@ -510,8 +510,16 @@ begin variable doit : std_ulogic; begin -- Read address mux and async RAM reading - even_rd_data := even_sprs(e_in.ramspr_even_rdaddr); - odd_rd_data := odd_sprs(e_in.ramspr_odd_rdaddr); + if is_X(e_in.ramspr_even_rdaddr) then + even_rd_data := (others => 'X'); + else + even_rd_data := even_sprs(to_integer(e_in.ramspr_even_rdaddr)); + end if; + if is_X(e_in.ramspr_even_rdaddr) then + odd_rd_data := (others => 'X'); + else + odd_rd_data := odd_sprs(to_integer(e_in.ramspr_odd_rdaddr)); + end if; -- Write address and data muxes doit := ex1.e.valid and not stage2_stall and not flush_in; @@ -559,13 +567,15 @@ begin begin if rising_edge(clk) then if ramspr_even_wr_enab = '1' then - even_sprs(ramspr_wr_addr) <= ramspr_even_wr_data; - report "writing even spr " & integer'image(ramspr_wr_addr) & " data=" & + assert not is_X(ramspr_wr_addr) report "Writing to unknown address" severity FAILURE; + even_sprs(to_integer(ramspr_wr_addr)) <= ramspr_even_wr_data; + report "writing even spr " & integer'image(to_integer(ramspr_wr_addr)) & " data=" & to_hstring(ramspr_even_wr_data); end if; if ramspr_odd_wr_enab = '1' then - odd_sprs(ramspr_wr_addr) <= ramspr_odd_wr_data; - report "writing odd spr " & integer'image(ramspr_wr_addr) & " data=" & + assert not is_X(ramspr_wr_addr) report "Writing to unknown address" severity FAILURE; + odd_sprs(to_integer(ramspr_wr_addr)) <= ramspr_odd_wr_data; + report "writing odd spr " & integer'image(to_integer(ramspr_wr_addr)) & " data=" & to_hstring(ramspr_odd_wr_data); end if; end if; @@ -1160,12 +1170,12 @@ begin when OP_MFMSR => when OP_MFSPR => if e_in.spr_is_ram = '1' then - if e_in.valid = '1' then + if e_in.valid = '1' and not is_X(e_in.insn) then report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & "=" & to_hstring(alu_result); end if; elsif e_in.spr_select.valid = '1' then - if e_in.valid = '1' then + if e_in.valid = '1' and not is_X(e_in.insn) then report "MFSPR to slow SPR " & integer'image(decode_spr_num(e_in.insn)); end if; slow_op := '1'; @@ -1182,7 +1192,7 @@ begin else -- mfspr from unimplemented SPRs should be a nop in -- supervisor mode and a program interrupt for user mode - if e_in.valid = '1' then + if e_in.valid = '1' and not is_X(e_in.insn) then report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & " invalid"; end if; @@ -1219,7 +1229,7 @@ begin end if; end if; when OP_MTSPR => - if e_in.valid = '1' then + if e_in.valid = '1' and not is_X(e_in.insn) then report "MTSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & "=" & to_hstring(c_in); end if; @@ -1773,8 +1783,8 @@ begin variable xer : std_ulogic_vector(63 downto 0); begin if sim_dump = '1' then - report "LR " & to_hstring(even_sprs(RAMSPR_LR)); - report "CTR " & to_hstring(odd_sprs(RAMSPR_CTR)); + report "LR " & to_hstring(even_sprs(to_integer(RAMSPR_LR))); + report "CTR " & to_hstring(odd_sprs(to_integer(RAMSPR_CTR))); sim_dump_done <= '1'; else sim_dump_done <= '0'; diff --git a/fetch1.vhdl b/fetch1.vhdl index af1dd6b..c6d26d7 100644 --- a/fetch1.vhdl +++ b/fetch1.vhdl @@ -123,15 +123,22 @@ begin raddr := unsigned(r.nia(BTC_ADDR_BITS + 1 downto 2)) + to_unsigned(2, BTC_ADDR_BITS); if advance_nia = '1' then - btc_rd_data <= btc_memory(to_integer(raddr)); - btc_rd_valid <= btc_valids(to_integer(raddr)); + if is_X(raddr) then + btc_rd_data <= (others => 'X'); + btc_rd_valid <= 'X'; + else + btc_rd_data <= btc_memory(to_integer(raddr)); + btc_rd_valid <= btc_valids(to_integer(raddr)); + end if; end if; if btc_wr = '1' then + assert not is_X(btc_wr_addr) report "Writing to unknown address" severity FAILURE; btc_memory(to_integer(unsigned(btc_wr_addr))) <= btc_wr_data; end if; if inval_btc = '1' or rst = '1' then btc_valids <= (others => '0'); elsif btc_wr = '1' then + assert not is_X(btc_wr_addr) report "Writing to unknown address" severity FAILURE; btc_valids(to_integer(unsigned(btc_wr_addr))) <= '1'; end if; end if; diff --git a/fpu.vhdl b/fpu.vhdl index 2dd221e..778422e 100644 --- a/fpu.vhdl +++ b/fpu.vhdl @@ -440,6 +440,10 @@ architecture behaviour of fpu is variable result: std_ulogic_vector(63 downto 0); begin result := (others => '0'); + if is_X(shift) then + result := (others => 'X'); + return result; + end if; for i in 0 to 63 loop if i >= shift then result(63 - i) := '1'; @@ -643,7 +647,11 @@ begin addrhi := "00"; end if; addr := addrhi & r.b.mantissa(UNIT_BIT - 1 downto UNIT_BIT - 8); - inverse_est <= '1' & inverse_table(to_integer(unsigned(addr))); + if is_X(addr) then + inverse_est <= (others => 'X'); + else + inverse_est <= '1' & inverse_table(to_integer(unsigned(addr))); + end if; end if; end process; @@ -841,10 +849,14 @@ begin new_exp := r.result_exp - r.shift; exp_tiny := '0'; exp_huge := '0'; - if new_exp < min_exp then + if is_X(new_exp) or is_X(min_exp) then + exp_tiny := 'X'; + elsif new_exp < min_exp then exp_tiny := '1'; end if; - if new_exp > max_exp then + if is_X(new_exp) or is_X(min_exp) then + exp_huge := 'X'; + elsif new_exp > max_exp then exp_huge := '1'; end if; @@ -855,7 +867,9 @@ begin pcmpb_eq := '1'; end if; pcmpb_lt := '0'; - if unsigned(r.p(59 downto 4)) < unsigned(r.b.mantissa(UNIT_BIT + 1 downto DP_RBIT)) then + if is_X(r.p(59 downto 4)) or is_X(r.b.mantissa(55 downto 0)) then + pcmpb_lt := 'X'; + elsif unsigned(r.p(59 downto 4)) < unsigned(r.b.mantissa(UNIT_BIT + 1 downto DP_RBIT)) then pcmpb_lt := '1'; end if; pcmpc_eq := '0'; @@ -863,7 +877,9 @@ begin pcmpc_eq := '1'; end if; pcmpc_lt := '0'; - if unsigned(r.p) < unsigned(r.c.mantissa) then + if is_X(r.p) or is_X(r.c.mantissa) then + pcmpc_lt := 'X'; + elsif unsigned(r.p) < unsigned(r.c.mantissa) then pcmpc_lt := '1'; end if; @@ -3014,7 +3030,9 @@ begin else mshift := r.shift; end if; - if mshift < to_signed(-64, EXP_BITS) then + if is_X(mshift) then + mask := (others => 'X'); + elsif mshift < to_signed(-64, EXP_BITS) then mask := (others => '1'); elsif mshift >= to_signed(0, EXP_BITS) then mask := (others => '0'); @@ -3060,7 +3078,9 @@ begin in_b0 := not in_b0; end if; in_b <= in_b0; - if r.shift >= to_signed(-64, EXP_BITS) and r.shift <= to_signed(63, EXP_BITS) then + if is_X(r.shift) then + shift_res := (others => 'X'); + elsif r.shift >= to_signed(-64, EXP_BITS) and r.shift <= to_signed(63, EXP_BITS) then shift_res := shifter_64(r.r(63 downto 1) & (shiftin0 or r.r(0)) & (shiftin or r.s(55)) & r.s(54 downto 0), std_ulogic_vector(r.shift(6 downto 0))); @@ -3224,7 +3244,9 @@ begin v.cr_mask := num_to_fxm(0); elsif r.is_cmp = '0' then v.cr_mask := num_to_fxm(1); - else + elsif is_X(insn_bf(r.insn)) then + v.cr_mask := (others => 'X'); + else v.cr_mask := num_to_fxm(to_integer(unsigned(insn_bf(r.insn)))); end if; v.writing_cr := r.is_cmp or r.rc; diff --git a/helpers.vhdl b/helpers.vhdl index bb69927..92c10dc 100644 --- a/helpers.vhdl +++ b/helpers.vhdl @@ -162,7 +162,9 @@ package body helpers is function ra_or_zero(ra: std_ulogic_vector(63 downto 0); reg: std_ulogic_vector(4 downto 0)) return std_ulogic_vector is begin - if to_integer(unsigned(reg)) = 0 then + if is_X(reg) then + return x"XXXXXXXXXXXXXXXX"; + elsif to_integer(unsigned(reg)) = 0 then return x"0000000000000000"; else return ra; diff --git a/icache.vhdl b/icache.vhdl index 394bc5e..9eb08c1 100644 --- a/icache.vhdl +++ b/icache.vhdl @@ -207,7 +207,6 @@ architecture rtl of icache is signal req_is_miss : std_ulogic; signal req_raddr : real_addr_t; - signal tlb_req_index : tlb_index_t; signal real_addr : real_addr_t; signal ra_valid : std_ulogic; signal priv_fault : std_ulogic; @@ -317,14 +316,15 @@ architecture rtl of icache is end; -- Simple hash for direct-mapped TLB index - function hash_ea(addr: std_ulogic_vector(63 downto 0)) return tlb_index_t is + function hash_ea(addr: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is variable hash : std_ulogic_vector(TLB_BITS - 1 downto 0); begin hash := addr(TLB_LG_PGSZ + TLB_BITS - 1 downto TLB_LG_PGSZ) xor addr(TLB_LG_PGSZ + 2 * TLB_BITS - 1 downto TLB_LG_PGSZ + TLB_BITS) xor addr(TLB_LG_PGSZ + 3 * TLB_BITS - 1 downto TLB_LG_PGSZ + 2 * TLB_BITS); - return to_integer(unsigned(hash)); + return hash; end; + begin assert LINE_SIZE mod ROW_SIZE = 0; @@ -435,7 +435,9 @@ begin process(all) begin -- PLRU interface - if get_index(r.hit_nia) = i then + if is_X(r.hit_nia) then + plru_acc_en <= 'X'; + elsif get_index(r.hit_nia) = i then plru_acc_en <= r.hit_valid; else plru_acc_en <= '0'; @@ -450,15 +452,25 @@ begin itlb_lookup : process(all) variable pte : tlb_pte_t; variable ttag : tlb_tag_t; + variable tlb_req_index : std_ulogic_vector(TLB_BITS - 1 downto 0); begin - tlb_req_index <= hash_ea(i_in.nia); - pte := itlb_ptes(tlb_req_index); - ttag := itlb_tags(tlb_req_index); + tlb_req_index := hash_ea(i_in.nia); + if is_X(tlb_req_index) then + pte := (others => 'X'); + ttag := (others => 'X'); + else + pte := itlb_ptes(to_integer(unsigned(tlb_req_index))); + ttag := itlb_tags(to_integer(unsigned(tlb_req_index))); + end if; if i_in.virt_mode = '1' then real_addr <= pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) & i_in.nia(TLB_LG_PGSZ - 1 downto 0); if ttag = i_in.nia(63 downto TLB_LG_PGSZ + TLB_BITS) then - ra_valid <= itlb_valids(tlb_req_index); + if is_X(tlb_req_index) then + ra_valid <= 'X'; + else + ra_valid <= itlb_valids(to_integer(unsigned(tlb_req_index))); + end if; else ra_valid <= '0'; end if; @@ -476,7 +488,7 @@ begin -- iTLB update itlb_update: process(clk) - variable wr_index : tlb_index_t; + variable wr_index : std_ulogic_vector(TLB_BITS - 1 downto 0); begin if rising_edge(clk) then wr_index := hash_ea(m_in.addr); @@ -486,12 +498,14 @@ begin itlb_valids(i) <= '0'; end loop; elsif m_in.tlbie = '1' then + assert not is_X(wr_index) report "icache index invalid on write" severity FAILURE; -- clear entry regardless of hit or miss - itlb_valids(wr_index) <= '0'; + itlb_valids(to_integer(unsigned(wr_index))) <= '0'; elsif m_in.tlbld = '1' then - itlb_tags(wr_index) <= m_in.addr(63 downto TLB_LG_PGSZ + TLB_BITS); - itlb_ptes(wr_index) <= m_in.pte; - itlb_valids(wr_index) <= '1'; + assert not is_X(wr_index) report "icache index invalid on write" severity FAILURE; + itlb_tags(to_integer(unsigned(wr_index))) <= m_in.addr(63 downto TLB_LG_PGSZ + TLB_BITS); + itlb_ptes(to_integer(unsigned(wr_index))) <= m_in.pte; + itlb_valids(to_integer(unsigned(wr_index))) <= '1'; end if; ev.itlb_miss_resolved <= m_in.tlbld and not rst; end if; @@ -503,9 +517,11 @@ begin variable hit_way : way_t; begin -- Extract line, row and tag from request - req_index <= get_index(i_in.nia); - req_row <= get_row(i_in.nia); - req_tag <= get_tag(real_addr, i_in.big_endian); + if not is_X(i_in.nia) then + req_index <= get_index(i_in.nia); + req_row <= get_row(i_in.nia); + end if; + req_tag <= get_tag(real_addr, i_in.big_endian); -- Calculate address of beginning of cache row, will be -- used for cache miss processing if needed @@ -517,7 +533,11 @@ begin hit_way := 0; is_hit := '0'; for i in way_t loop - if i_in.req = '1' and + if is_X(i_in.nia) then + -- FIXME: This is fragile + -- req_index or req_row could be a metavalue + is_hit := 'X'; + elsif i_in.req = '1' and (cache_valids(req_index)(i) = '1' or (r.state = WAIT_ACK and req_index = r.store_index and @@ -556,7 +576,7 @@ begin -- some of the cache geometry information. -- if r.hit_valid = '1' then - i_out.insn <= read_insn_word(r.hit_nia, cache_out(r.hit_way)); + i_out.insn <= read_insn_word(r.hit_nia, cache_out(r.hit_way)); else i_out.insn <= (others => '0'); end if; @@ -592,6 +612,8 @@ begin r.hit_valid <= req_is_hit; if req_is_hit = '1' then r.hit_way <= req_hit_way; + -- this is a bit fragile but better than propogating bad values + assert not is_X(i_in.nia) report "metavalue in NIA" severity FAILURE; report "cache hit nia:" & to_hstring(i_in.nia) & " IR:" & std_ulogic'image(i_in.virt_mode) & @@ -648,6 +670,9 @@ begin snoop_addr := addr_to_real(wb_to_addr(wb_snoop_in.adr)); snoop_index <= get_index(snoop_addr); snoop_cache_tags := cache_tags(get_index(snoop_addr)); + if snoop_valid = '1' and is_X(snoop_addr) then + report "metavalue in snoop_addr" severity FAILURE; + end if; snoop_tag := get_tag(snoop_addr, '0'); snoop_hits <= (others => '0'); for i in way_t loop diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 0a2f088..439f124 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -625,8 +625,12 @@ begin byte_offset := unsigned(r1.addr0(2 downto 0)); for i in 0 to 7 loop k := (to_unsigned(i, 3) - byte_offset) xor r1.req.brev_mask; - j := to_integer(k) * 8; - store_data(i * 8 + 7 downto i * 8) <= r1.req.store_data(j + 7 downto j); + if is_X(k) then + store_data(i * 8 + 7 downto i * 8) <= (others => 'X'); + else + j := to_integer(k) * 8; + store_data(i * 8 + 7 downto i * 8) <= r1.req.store_data(j + 7 downto j); + end if; end loop; dbg_spr_rd := dbg_spr_req and not (r1.req.valid and r1.req.read_spr); @@ -757,8 +761,12 @@ begin -- load data formatting -- shift and byte-reverse data bytes for i in 0 to 7 loop - j := to_integer(r2.byte_index(i)) * 8; - data_permuted(i * 8 + 7 downto i * 8) := d_in.data(j + 7 downto j); + if is_X(r2.byte_index(i)) then + data_permuted(i * 8 + 7 downto i * 8) := (others => 'X'); + else + j := to_integer(r2.byte_index(i)) * 8; + data_permuted(i * 8 + 7 downto i * 8) := d_in.data(j + 7 downto j); + end if; end loop; -- Work out the sign bit for sign extension. @@ -779,7 +787,9 @@ begin -- trim and sign-extend for i in 0 to 7 loop - if i < to_integer(unsigned(r2.req.length)) then + if is_X(r2.req.length) then + trim_ctl(i) := "XX"; + elsif i < to_integer(unsigned(r2.req.length)) then if r2.req.dword_index = '1' then trim_ctl(i) := '1' & not r2.use_second(i); else diff --git a/mmu.vhdl b/mmu.vhdl index d95cd3c..1774822 100644 --- a/mmu.vhdl +++ b/mmu.vhdl @@ -163,11 +163,15 @@ begin begin -- mask_count has to be >= 5 m := x"001f"; - for i in 5 to 15 loop - if i < to_integer(r.mask_size) then - m(i) := '1'; - end if; - end loop; + if is_X(r.mask_size) then + m := (others => 'X'); + else + for i in 5 to 15 loop + if i < to_integer(r.mask_size) then + m(i) := '1'; + end if; + end loop; + end if; mask <= m; end process; @@ -178,7 +182,9 @@ begin begin m := (others => '0'); for i in 0 to 43 loop - if i < to_integer(r.shift) then + if is_X(r.shift) then + m(i) := 'X'; + elsif i < to_integer(r.shift) then m(i) := '1'; end if; end loop; diff --git a/pmu.vhdl b/pmu.vhdl index 2967f4e..928d6c2 100644 --- a/pmu.vhdl +++ b/pmu.vhdl @@ -217,7 +217,11 @@ begin -- Check for timebase events tbdiff := p_in.tbbits and not prev_tb; - tbbit := tbdiff(3 - to_integer(unsigned(mmcr0(MMCR0_TBSEL + 1 downto MMCR0_TBSEL)))); + if is_X(mmcr0) then + tbbit := 'X'; + else + tbbit := tbdiff(3 - to_integer(unsigned(mmcr0(MMCR0_TBSEL + 1 downto MMCR0_TBSEL)))); + end if; if tbbit = '1' and mmcr0(MMCR0_TBEE) = '1' then event := '1'; end if; diff --git a/register_file.vhdl b/register_file.vhdl index 753ce80..e56202a 100644 --- a/register_file.vhdl +++ b/register_file.vhdl @@ -120,9 +120,21 @@ begin b_addr(5) := '0'; c_addr(5) := '0'; end if; - data_1 <= registers(to_integer(unsigned(a_addr))); - data_2 <= registers(to_integer(unsigned(b_addr))); - data_3 <= registers(to_integer(unsigned(c_addr))); + if is_X(a_addr) then + data_1 <= (others => 'X'); + else + data_1 <= registers(to_integer(unsigned(a_addr))); + end if; + if is_X(b_addr) then + data_2 <= (others => 'X'); + else + data_2 <= registers(to_integer(unsigned(b_addr))); + end if; + if is_X(c_addr) then + data_3 <= (others => 'X'); + else + data_3 <= registers(to_integer(unsigned(c_addr))); + end if; prev_write_data <= w_in.write_data; end if; diff --git a/rotator.vhdl b/rotator.vhdl index 45913c9..1049e20 100644 --- a/rotator.vhdl +++ b/rotator.vhdl @@ -34,6 +34,10 @@ architecture behaviour of rotator is variable ret: std_ulogic_vector(63 downto 0); begin ret := (others => '0'); + if is_X(mask_begin) then + ret := (others => 'X'); + return ret; + end if; for i in 0 to 63 loop if i >= to_integer(unsigned(mask_begin)) then ret(63 - i) := '1'; diff --git a/scripts/run_test.sh b/scripts/run_test.sh index 185c3a6..1a032ba 100755 --- a/scripts/run_test.sh +++ b/scripts/run_test.sh @@ -25,9 +25,6 @@ ${MICROWATT_DIR}/core_tb | sed 's/.*: //' | egrep '^(GPR[0-9]|LR |CTR |XER |CR [ grep -v "^$" ${MICROWATT_DIR}/tests/${TEST}.out | sort | grep -v GPR31 > exp.out -cp test.out /tmp -cp exp.out /tmp - diff -q test.out exp.out && echo "$TEST PASS" && exit 0 echo "$TEST FAIL ********" diff --git a/scripts/run_test_console.sh b/scripts/run_test_console.sh index 1aaa2bb..95c2495 100755 --- a/scripts/run_test_console.sh +++ b/scripts/run_test_console.sh @@ -3,7 +3,7 @@ # Runs a test and checks the console output against known good output if [ $# -ne 1 ]; then - echo "Usage: run_test.sh " + echo "Usage: run_test_console.sh " exit 1 fi @@ -23,16 +23,21 @@ cd $TMPDIR cp ${MICROWATT_DIR}/tests/${TEST}.bin main_ram.bin -${MICROWATT_DIR}/core_tb > /dev/null 2> test1.out || true +${MICROWATT_DIR}/core_tb > console.out 2> test1.out || true + +# check metavalues aren't increasing +COUNT=$(grep -c 'metavalue' console.out) +EXP=$(cat ${MICROWATT_DIR}/tests/${TEST}.metavalue) +if [[ $COUNT -gt $EXP ]] ; then + echo "$TEST FAIL ******** metavalues increased from $EXP to $COUNT" + exit 1 +fi grep -v "Failed to bind debug socket" test1.out > test.out cp ${MICROWATT_DIR}/tests/${TEST}.console_out exp.out -cp test.out /tmp -cp exp.out /tmp - diff -q test.out exp.out && echo "$TEST PASS" && exit 0 -echo "$TEST FAIL ********" +echo "$TEST FAIL ******** Console output changed" exit 1 diff --git a/tests/test_decrementer.metavalue b/tests/test_decrementer.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_decrementer.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_fpu.bin b/tests/test_fpu.bin index dee8fbd..3c1021b 100755 Binary files a/tests/test_fpu.bin and b/tests/test_fpu.bin differ diff --git a/tests/test_fpu.console_out b/tests/test_fpu.console_out index ed759a5..3ec9480 100644 --- a/tests/test_fpu.console_out +++ b/tests/test_fpu.console_out @@ -21,3 +21,5 @@ test 20:PASS test 21:PASS test 22:PASS test 23:PASS +test 24:PASS +test 25:PASS diff --git a/tests/test_fpu.metavalue b/tests/test_fpu.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_fpu.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_illegal.metavalue b/tests/test_illegal.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_illegal.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_misc.metavalue b/tests/test_misc.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_misc.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_mmu.metavalue b/tests/test_mmu.metavalue new file mode 100644 index 0000000..a29644e --- /dev/null +++ b/tests/test_mmu.metavalue @@ -0,0 +1 @@ +144 diff --git a/tests/test_modes.metavalue b/tests/test_modes.metavalue new file mode 100644 index 0000000..492dff0 --- /dev/null +++ b/tests/test_modes.metavalue @@ -0,0 +1 @@ +152 diff --git a/tests/test_pmu.metavalue b/tests/test_pmu.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_pmu.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_privileged.metavalue b/tests/test_privileged.metavalue new file mode 100644 index 0000000..492dff0 --- /dev/null +++ b/tests/test_privileged.metavalue @@ -0,0 +1 @@ +152 diff --git a/tests/test_reservation.metavalue b/tests/test_reservation.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_reservation.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_sc.metavalue b/tests/test_sc.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_sc.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_spr_read.metavalue b/tests/test_spr_read.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_spr_read.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_trace.metavalue b/tests/test_trace.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_trace.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/test_xics.metavalue b/tests/test_xics.metavalue new file mode 100644 index 0000000..415196e --- /dev/null +++ b/tests/test_xics.metavalue @@ -0,0 +1 @@ +118 diff --git a/tests/update_console_tests b/tests/update_console_tests index b168e8d..d0613c8 100755 --- a/tests/update_console_tests +++ b/tests/update_console_tests @@ -9,6 +9,7 @@ for i in sc illegal decrementer xics privileged mmu misc modes pmu reservation t cd - cp $i/$i.bin test_$i.bin ln -s test_$i.bin main_ram.bin - ../core_tb > /dev/null 2> test_$i.console_out - rm main_ram.bin + ../core_tb > test_$i.log_out 2> test_$i.console_out + grep -c metavalue test_$i.log_out > test_$i.metavalue + rm main_ram.bin test_$i.log_out done