decode1: Work out register addresses in decode1
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 21 Feb 2022 08:29:09 +0000 (19:29 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 22 Jul 2022 12:20:52 +0000 (22:20 +1000)
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 <paulus@ozlabs.org>
common.vhdl
core.vhdl
decode1.vhdl
register_file.vhdl

index 39ebfb1ba1d47341e88ba9110639d73148bb7043..0349a6e665d3a92601f06778b07c74a824a9abca 100644 (file)
@@ -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);
index 641c12d16dcc4a419efe1efcf448b29ce6f44bac..764141a86701a1f5bd68bf19d76db8999527d763 100644 (file)
--- 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,
index 5ee7b5743cbf989fa272683b71a9d41d5b9c87e5..36d511b69ee8a1674b898ca512eda562c24c7f2b 100644 (file)
@@ -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
index dcce0a4c9784a97092ad79deb4fbda5cd531652a..bc40c3f5675f4d0121d9b0511d074cf65f76cbee 100644 (file)
@@ -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;