Plumb insn_type through to loadstore1
authorPaul Mackerras <paulus@ozlabs.org>
Fri, 3 Apr 2020 03:50:17 +0000 (14:50 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 28 Apr 2020 21:52:50 +0000 (07:52 +1000)
In preparation for adding a TLB to the dcache, this plumbs the
insn_type from execute1 through to loadstore1, so that we can have
other operations besides loads and stores (e.g. tlbie) going to
loadstore1 and thence to the dcache.  This also plumbs the unit field
of the decode ROM from decode2 through to execute1 to simplify the
logic around which ops need to go to loadstore1.

The load and store data formatting are now not conditional on the
op being OP_LOAD or OP_STORE.  This eliminates the inferred latches
clocked by each of the bits of r.op that we were getting previously.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Makefile
common.vhdl
decode2.vhdl
execute1.vhdl
loadstore1.vhdl

index 8c3133d79efc79ea0b22c7357e5194f9543d0930..c09696a92d7784afe5f620c833ce1ab3e428cac5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -58,7 +58,7 @@ icache_tb.o: common.o wishbone_types.o icache.o wishbone_bram_wrapper.o
 dcache.o: utils.o common.o wishbone_types.o plru.o cache_ram.o utils.o
 dcache_tb.o: common.o wishbone_types.o dcache.o wishbone_bram_wrapper.o
 insn_helpers.o:
-loadstore1.o: common.o helpers.o
+loadstore1.o: common.o helpers.o decode_types.o
 logical.o: decode_types.o
 multiply_tb.o: decode_types.o common.o glibc_random.o ppc_fx_insns.o multiply.o
 multiply.o: common.o decode_types.o
index 9041d324f1578686536713a35ceb37cd539aa152..65e40c102723a2e4fccadd2540c2be8eda6a5948 100644 (file)
@@ -118,6 +118,7 @@ package common is
 
     type Decode2ToExecute1Type is record
        valid: std_ulogic;
+        unit : unit_t;
        insn_type: insn_type_t;
        nia: std_ulogic_vector(63 downto 0);
        write_reg: gspr_index_t;
@@ -150,7 +151,7 @@ package common is
         reserve : std_ulogic;                           -- set for larx/stcx
     end record;
     constant Decode2ToExecute1Init : Decode2ToExecute1Type :=
-       (valid => '0', insn_type => OP_ILLEGAL, bypass_data1 => '0', bypass_data2 => '0', bypass_data3 => '0',
+       (valid => '0', unit => NONE, insn_type => OP_ILLEGAL, bypass_data1 => '0', bypass_data2 => '0', bypass_data3 => '0',
          lr => '0', rc => '0', oe => '0', invert_a => '0',
         invert_out => '0', input_carry => ZERO, output_carry => '0', input_cr => '0', output_cr => '0',
         is_32bit => '0', is_signed => '0', xerc => xerc_init, reserve => '0',
@@ -213,7 +214,7 @@ package common is
 
     type Execute1ToLoadstore1Type is record
        valid : std_ulogic;
-       load : std_ulogic;                              -- is this a load or store
+        op : insn_type_t;                               -- what ld/st op to do
        addr1 : std_ulogic_vector(63 downto 0);
        addr2 : std_ulogic_vector(63 downto 0);
        data : std_ulogic_vector(63 downto 0);          -- data to write, unused for read
@@ -228,7 +229,7 @@ package common is
         reserve : std_ulogic;                           -- set for larx/stcx.
         rc : std_ulogic;                                -- set for stcx.
     end record;
-    constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', load => '0', ci => '0', byte_reverse => '0',
+    constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0',
                                                                      sign_extend => '0', update => '0', xerc => xerc_init,
                                                                      reserve => '0', rc => '0', others => (others => '0'));
 
index ff773aa58ffacc824a0fae8477188f74dabb54ce..edcc50cff97f1aab11037727478446e70430d588 100644 (file)
@@ -304,6 +304,7 @@ begin
 
                -- execute unit
                v.e.nia := d_in.nia;
+                v.e.unit := d_in.decode.unit;
                v.e.insn_type := d_in.decode.insn_type;
                v.e.read_reg1 := decoded_reg_a.reg;
                v.e.read_data1 := decoded_reg_a.data;
index 9153b378e58c5ee5d8b8860201abadd592eb21da..abd4a18b0d8678714472d1323831a384b89c7133 100644 (file)
@@ -464,7 +464,7 @@ begin
             ctrl_tmp.srr1(63 - 45) <= '1';
             report "privileged instruction";
             
-       elsif e_in.valid = '1' then
+       elsif e_in.valid = '1' and e_in.unit = ALU then
 
            v.e.valid := '1';
            v.e.write_reg := e_in.write_reg;
@@ -844,11 +844,6 @@ begin
                stall_out <= '1';
                x_to_divider.valid <= '1';
 
-            when OP_LOAD | OP_STORE =>
-                -- loadstore/dcache has its own port to writeback
-                v.e.valid := '0';
-                lv.valid := '1';
-
             when others =>
                terminate_out <= '1';
                report "illegal";
@@ -874,6 +869,14 @@ begin
                report "Delayed LR update to " & to_hstring(next_nia);
                stall_out <= '1';
            end if;
+
+        elsif e_in.valid = '1' then
+            -- instruction for other units, i.e. LDST
+            v.e.valid := '0';
+            if e_in.unit = LDST then
+                lv.valid := '1';
+            end if;
+
        elsif r.lr_update = '1' then
            result_en := '1';
            result := r.next_lr;
@@ -940,9 +943,7 @@ begin
        v.e.write_enable := result_en;
 
         -- Outputs to loadstore1 (async)
-        if e_in.insn_type = OP_LOAD then
-            lv.load := '1';
-        end if;
+        lv.op := e_in.insn_type;
         lv.addr1 := a_in;
         lv.addr2 := b_in;
         lv.data := c_in;
index 518feee54f28ff088fdf54e97ef2b5521ced1e77..664e3965de326ecb6063db6546db9bb80f213d3d 100644 (file)
@@ -3,6 +3,7 @@ use ieee.std_logic_1164.all;
 use ieee.numeric_std.all;
 
 library work;
+use work.decode_types.all;
 use work.common.all;
 use work.helpers.all;
 
@@ -41,7 +42,7 @@ architecture behave of loadstore1 is
 
     type reg_stage_t is record
         -- latch most of the input request
-       load         : std_ulogic;
+        load         : std_ulogic;
        addr         : std_ulogic_vector(63 downto 0);
        store_data   : std_ulogic_vector(63 downto 0);
        load_data    : std_ulogic_vector(63 downto 0);
@@ -146,59 +147,60 @@ begin
         two_dwords := or (r.second_bytes);
 
         -- load data formatting
-        if r.load = '1' then
-            byte_offset := unsigned(r.addr(2 downto 0));
-            brev_lenm1 := "000";
-            if r.byte_reverse = '1' then
-                brev_lenm1 := unsigned(r.length(2 downto 0)) - 1;
-            end if;
+        byte_offset := unsigned(r.addr(2 downto 0));
+        brev_lenm1 := "000";
+        if r.byte_reverse = '1' then
+            brev_lenm1 := unsigned(r.length(2 downto 0)) - 1;
+        end if;
 
-            -- shift and byte-reverse data bytes
-            for i in 0 to 7 loop
-                kk := ('0' & (to_unsigned(i, 3) xor brev_lenm1)) + ('0' & byte_offset);
-                use_second(i) := kk(3);
-                j := to_integer(kk(2 downto 0)) * 8;
-                data_permuted(i * 8 + 7 downto i * 8) := d_in.data(j + 7 downto j);
-            end loop;
-
-            -- Work out the sign bit for sign extension.
-            -- Assumes we are not doing both sign extension and byte reversal,
-            -- in that for unaligned loads crossing two dwords we end up
-            -- using a bit from the second dword, whereas for a byte-reversed
-            -- (i.e. big-endian) load the sign bit would be in the first dword.
-            negative := (r.length(3) and data_permuted(63)) or
-                        (r.length(2) and data_permuted(31)) or
-                        (r.length(1) and data_permuted(15)) or
-                        (r.length(0) and data_permuted(7));
-
-            -- trim and sign-extend
-            for i in 0 to 7 loop
-                if i < to_integer(unsigned(r.length)) then
-                    if two_dwords = '1' then
-                        trim_ctl(i) := '1' & not use_second(i);
-                    else
-                        trim_ctl(i) := not use_second(i) & '0';
-                    end if;
+        -- shift and byte-reverse data bytes
+        for i in 0 to 7 loop
+            kk := ('0' & (to_unsigned(i, 3) xor brev_lenm1)) + ('0' & byte_offset);
+            use_second(i) := kk(3);
+            j := to_integer(kk(2 downto 0)) * 8;
+            data_permuted(i * 8 + 7 downto i * 8) := d_in.data(j + 7 downto j);
+        end loop;
+
+        -- Work out the sign bit for sign extension.
+        -- Assumes we are not doing both sign extension and byte reversal,
+        -- in that for unaligned loads crossing two dwords we end up
+        -- using a bit from the second dword, whereas for a byte-reversed
+        -- (i.e. big-endian) load the sign bit would be in the first dword.
+        negative := (r.length(3) and data_permuted(63)) or
+                    (r.length(2) and data_permuted(31)) or
+                    (r.length(1) and data_permuted(15)) or
+                    (r.length(0) and data_permuted(7));
+
+        -- trim and sign-extend
+        for i in 0 to 7 loop
+            if i < to_integer(unsigned(r.length)) then
+                if two_dwords = '1' then
+                    trim_ctl(i) := '1' & not use_second(i);
                 else
-                    trim_ctl(i) := '0' & (negative and r.sign_extend);
+                    trim_ctl(i) := not use_second(i) & '0';
                 end if;
-                case trim_ctl(i) is
-                    when "11" =>
-                        data_trimmed(i * 8 + 7 downto i * 8) := r.load_data(i * 8 + 7 downto i * 8);
-                    when "10" =>
-                        data_trimmed(i * 8 + 7 downto i * 8) := data_permuted(i * 8 + 7 downto i * 8);
-                    when "01" =>
-                        data_trimmed(i * 8 + 7 downto i * 8) := x"FF";
-                    when others =>
-                        data_trimmed(i * 8 + 7 downto i * 8) := x"00";
-                end case;
-            end loop;
-        end if;
+            else
+                trim_ctl(i) := '0' & (negative and r.sign_extend);
+            end if;
+            case trim_ctl(i) is
+                when "11" =>
+                    data_trimmed(i * 8 + 7 downto i * 8) := r.load_data(i * 8 + 7 downto i * 8);
+                when "10" =>
+                    data_trimmed(i * 8 + 7 downto i * 8) := data_permuted(i * 8 + 7 downto i * 8);
+                when "01" =>
+                    data_trimmed(i * 8 + 7 downto i * 8) := x"FF";
+                when others =>
+                    data_trimmed(i * 8 + 7 downto i * 8) := x"00";
+            end case;
+        end loop;
 
         case r.state is
         when IDLE =>
             if l_in.valid = '1' then
-                v.load := l_in.load;
+                v.load := '0';
+                if l_in.op = OP_LOAD then
+                    v.load := '1';
+                end if;
                 v.addr := lsu_sum;
                 v.write_reg := l_in.write_reg;
                 v.length := l_in.length;
@@ -229,18 +231,16 @@ begin
                 v.addr := lsu_sum;
 
                 -- Do byte reversing and rotating for stores in the first cycle
-                if v.load = '0' then
-                    byte_offset := unsigned(lsu_sum(2 downto 0));
-                    brev_lenm1 := "000";
-                    if l_in.byte_reverse = '1' then
-                        brev_lenm1 := unsigned(l_in.length(2 downto 0)) - 1;
-                    end if;
-                    for i in 0 to 7 loop
-                        k := (to_unsigned(i, 3) xor brev_lenm1) + byte_offset;
-                        j := to_integer(k) * 8;
-                        v.store_data(j + 7 downto j) := l_in.data(i * 8 + 7 downto i * 8);
-                    end loop;
+                byte_offset := unsigned(lsu_sum(2 downto 0));
+                brev_lenm1 := "000";
+                if l_in.byte_reverse = '1' then
+                    brev_lenm1 := unsigned(l_in.length(2 downto 0)) - 1;
                 end if;
+                for i in 0 to 7 loop
+                    k := (to_unsigned(i, 3) xor brev_lenm1) + byte_offset;
+                    j := to_integer(k) * 8;
+                    v.store_data(j + 7 downto j) := l_in.data(i * 8 + 7 downto i * 8);
+                end loop;
 
                 req := '1';
                 stall := '1';