From: Paul Mackerras Date: Mon, 21 Feb 2022 08:29:09 +0000 (+1100) Subject: decode1: Work out register addresses in decode1 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=06c13d4988fee4ec1f5bf089ad71f2acc2883818;p=microwatt.git decode1: Work out register addresses in decode1 This adds some relatively simple logic to decode1 to compute the GPR/FPR addresses that an instruction will access. It always computes three addresses regardless of whether the instruction will actually use all of them. The main things it computes are whether the instruction uses the RS field or the RC field for the 3rd operand, and whether the operands are FPRs or GPRs (it is possible for RS to be an FPR but RA and RB to be GPRs, as for example with stfdx). At the moment all we do with these computed register addresses is to assert that they are identical to the ones coming from decode2 one cycle later. Signed-off-by: Paul Mackerras --- diff --git a/common.vhdl b/common.vhdl index 39ebfb1..0349a6e 100644 --- a/common.vhdl +++ b/common.vhdl @@ -276,6 +276,12 @@ package common is redirect_nia : std_ulogic_vector(63 downto 0); end record; + type Decode1ToRegisterFileType is record + reg_1_addr : gspr_index_t; + reg_2_addr : gspr_index_t; + reg_3_addr : gspr_index_t; + end record; + type bypass_data_t is record tag : instr_tag_t; data : std_ulogic_vector(63 downto 0); diff --git a/core.vhdl b/core.vhdl index 641c12d..764141a 100644 --- a/core.vhdl +++ b/core.vhdl @@ -63,6 +63,7 @@ architecture behave of core is -- decode signals signal decode1_to_decode2: Decode1ToDecode2Type; signal decode1_to_fetch1: Decode1ToFetch1Type; + signal decode1_to_register_file: Decode1ToRegisterFileType; signal decode2_to_execute1: Decode2ToExecute1Type; -- register file signals @@ -285,6 +286,7 @@ begin f_in => icache_to_decode1, d_out => decode1_to_decode2, f_out => decode1_to_fetch1, + r_out => decode1_to_register_file, log_out => log_data(109 downto 97) ); @@ -329,6 +331,8 @@ begin ) port map ( clk => clk, + stall => decode2_stall_out, + d1_in => decode1_to_register_file, d_in => decode2_to_register_file, d_out => register_file_to_decode2, w_in => writeback_to_register_file, diff --git a/decode1.vhdl b/decode1.vhdl index 5ee7b57..36d511b 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -5,6 +5,7 @@ use ieee.numeric_std.all; library work; use work.common.all; use work.decode_types.all; +use work.insn_helpers.all; entity decode1 is generic ( @@ -24,6 +25,7 @@ entity decode1 is f_in : in IcacheToDecode1Type; f_out : out Decode1ToFetch1Type; d_out : out Decode1ToDecode2Type; + r_out : out Decode1ToRegisterFileType; log_out : out std_ulogic_vector(12 downto 0) ); end entity decode1; @@ -628,6 +630,7 @@ begin decode1_1: process(all) variable v : Decode1ToDecode2Type; + variable vr : Decode1ToRegisterFileType; variable vi : reg_internal_t; variable majorop : major_opcode_t; variable minor4op : std_ulogic_vector(10 downto 0); @@ -636,6 +639,8 @@ begin variable br_target : std_ulogic_vector(61 downto 0); variable br_offset : signed(23 downto 0); variable bv : br_predictor_t; + variable fprs, fprabc : std_ulogic; + variable in3rc : std_ulogic; begin v := Decode1ToDecode2Init; vi := reg_internal_t_init; @@ -646,6 +651,10 @@ begin v.stop_mark := f_in.stop_mark; v.big_endian := f_in.big_endian; + fprs := '0'; + fprabc := '0'; + in3rc := '0'; + if f_in.valid = '1' then report "Decode insn " & to_hstring(f_in.insn) & " at " & to_hstring(f_in.nia); end if; @@ -665,6 +674,7 @@ begin minor4op := f_in.insn(5 downto 0) & f_in.insn(10 downto 6); vi.override := not decode_op_4_valid(to_integer(unsigned(minor4op))); v.decode := decode_op_4_array(to_integer(unsigned(f_in.insn(5 downto 0)))); + in3rc := '1'; when 31 => -- major opcode 31, lots of things @@ -688,6 +698,10 @@ begin when others => end case; 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 => -- Predict backward branches as taken, forward as untaken @@ -715,6 +729,12 @@ begin when 30 => v.decode := decode_op_30_array(to_integer(unsigned(f_in.insn(4 downto 1)))); + when 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)))); @@ -725,6 +745,9 @@ begin if f_in.insn(5) = '0' and not std_match(f_in.insn(10 downto 1), "11-1001110") then vi.override := '1'; end if; + in3rc := '1'; + fprabc := '1'; + fprs := '1'; end if; when 62 => @@ -738,11 +761,23 @@ begin else v.decode := decode_op_63h_array(to_integer(unsigned(f_in.insn(4 downto 1)))); end if; + in3rc := '1'; + fprabc := '1'; + fprs := '1'; end if; when others => end case; + -- Work out GPR/FPR read addresses + vr.reg_1_addr := fprabc & insn_ra(f_in.insn); + vr.reg_2_addr := fprabc & insn_rb(f_in.insn); + if in3rc = '1' then + vr.reg_3_addr := fprabc & insn_rcreg(f_in.insn); + else + vr.reg_3_addr := fprs & insn_rs(f_in.insn); + end if; + if f_in.fetch_failed = '1' then v.valid := '1'; vi.override := '1'; @@ -788,6 +823,8 @@ begin f_out.redirect <= br.predict; f_out.redirect_nia <= br_target & "00"; flush_out <= bv.predict or br.predict; + + r_out <= vr; end process; d1_log: if LOG_LENGTH > 0 generate diff --git a/register_file.vhdl b/register_file.vhdl index dcce0a4..bc40c3f 100644 --- a/register_file.vhdl +++ b/register_file.vhdl @@ -14,7 +14,9 @@ entity register_file is ); port( clk : in std_logic; + stall : in std_ulogic; + d1_in : in Decode1ToRegisterFileType; d_in : in Decode2ToRegisterFileType; d_out : out RegisterFileToDecode2Type; @@ -39,9 +41,13 @@ architecture behaviour of register_file is signal rd_port_b : std_ulogic_vector(63 downto 0); signal dbg_data : std_ulogic_vector(63 downto 0); signal dbg_ack : std_ulogic; + signal addr_1_reg : gspr_index_t; + signal addr_2_reg : gspr_index_t; + signal addr_3_reg : gspr_index_t; begin -- synchronous writes register_write_0: process(clk) + variable a_addr, b_addr, c_addr : gspr_index_t; variable w_addr : gspr_index_t; begin if rising_edge(clk) then @@ -56,6 +62,19 @@ begin assert not(is_x(w_in.write_data)) and not(is_x(w_in.write_reg)) severity failure; registers(to_integer(unsigned(w_addr))) <= w_in.write_data; end if; + + a_addr := d1_in.reg_1_addr; + b_addr := d1_in.reg_2_addr; + c_addr := d1_in.reg_3_addr; + + if stall = '0' then + addr_1_reg <= a_addr; + addr_2_reg <= b_addr; + addr_3_reg <= c_addr; + end if; + assert (d_in.read1_enable = '0') or (d_in.read1_reg = addr_1_reg) severity failure; + assert (d_in.read2_enable = '0') or (d_in.read2_reg = addr_2_reg) severity failure; + assert (d_in.read3_enable = '0') or (d_in.read3_reg = addr_3_reg) severity failure; end if; end process register_write_0;