Restore debug access to SPRs
authorPaul Mackerras <paulus@ozlabs.org>
Fri, 25 Feb 2022 05:46:34 +0000 (16:46 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 22 Jul 2022 12:20:42 +0000 (22:20 +1000)
This provides access to the SPRs via the JTAG DMI interface.  For now
they are still accessed as if they were GPR/FPRs using the same
numbering as before (GPRs at 0 - 0x1f, SPRs at 0x20 - 0x2d, FPRs at
0x40 - 0x5f).

For XER, debug reads now report the full value, not just the bits that
were previously stored in the register file.  The "slow" SPR mux is
not used for debug reads.

Decode2 determines on each cycle whether a debug SPR access will
happen next cycle, based on whether there is a request and whether the
current instruction accesses the SPR RAM.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
common.vhdl
core.vhdl
core_debug.vhdl
decode2.vhdl
execute1.vhdl
scripts/mw_debug/mw_debug.c

index 06b62e0f71e3fba009fe508c81a81949fce88a12..d743c2d5b5a2754f2417c4d246810dce1ff1ef17 100644 (file)
@@ -337,6 +337,7 @@ package common is
         ramspr_wraddr      : ramspr_index;
         ramspr_write_even  : std_ulogic;
         ramspr_write_odd   : std_ulogic;
+        dbg_spr_access : std_ulogic;
         dec_ctr : std_ulogic;
     end record;
     constant Decode2ToExecute1Init : Decode2ToExecute1Type :=
@@ -354,6 +355,7 @@ package common is
          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',
+         dbg_spr_access => '0',
          dec_ctr => '0',
          others => (others => '0'));
 
index 82c66b48717b642547fcb345e9e8c93664698e4d..a91b72983f064b117d125aa47aeafd3cb18c2aaf 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -150,6 +150,10 @@ architecture behave of core is
     signal dbg_gpr_ack : std_ulogic;
     signal dbg_gpr_addr : gspr_index_t;
     signal dbg_gpr_data : std_ulogic_vector(63 downto 0);
+    signal dbg_spr_req : std_ulogic;
+    signal dbg_spr_ack : std_ulogic;
+    signal dbg_spr_addr : std_ulogic_vector(7 downto 0);
+    signal dbg_spr_data : std_ulogic_vector(63 downto 0);
 
     signal ctrl_debug : ctrl_t;
 
@@ -307,6 +311,8 @@ begin
             execute2_bypass => execute2_bypass,
             execute2_cr_bypass => execute2_cr_bypass,
             writeback_bypass => writeback_bypass,
+            dbg_spr_req => dbg_spr_req,
+            dbg_spr_addr => dbg_spr_addr,
             log_out => log_data(119 downto 110)
             );
     decode2_busy_in <= ex1_busy_out;
@@ -378,6 +384,10 @@ begin
             dc_events => dcache_events,
             ic_events => icache_events,
             terminate_out => terminate,
+            dbg_spr_req => dbg_spr_req,
+            dbg_spr_ack => dbg_spr_ack,
+            dbg_spr_addr => dbg_spr_addr,
+            dbg_spr_data => dbg_spr_data,
             sim_dump => sim_ex_dump,
             sim_dump_done => sim_cr_dump,
             log_out => log_data(134 downto 120),
@@ -504,6 +514,10 @@ begin
             dbg_gpr_ack => dbg_gpr_ack,
             dbg_gpr_addr => dbg_gpr_addr,
             dbg_gpr_data => dbg_gpr_data,
+            dbg_spr_req => dbg_spr_req,
+            dbg_spr_ack => dbg_spr_ack,
+            dbg_spr_addr => dbg_spr_addr,
+            dbg_spr_data => dbg_spr_data,
             log_data => log_data,
             log_read_addr => log_rd_addr,
             log_read_data => log_rd_data,
index ff99df4cb0e5d203db96a209951f7ab22747eb09..a1d4a942b697f18c8e54b0de66ec2130422db7b6 100644 (file)
@@ -33,12 +33,18 @@ entity core_debug is
         nia             : in std_ulogic_vector(63 downto 0);
         msr             : in std_ulogic_vector(63 downto 0);
 
-        -- GSPR register read port
+        -- GPR/FPR register read port
         dbg_gpr_req     : out std_ulogic;
         dbg_gpr_ack     : in std_ulogic;
         dbg_gpr_addr    : out gspr_index_t;
         dbg_gpr_data    : in std_ulogic_vector(63 downto 0);
 
+        -- SPR register read port
+        dbg_spr_req     : out std_ulogic;
+        dbg_spr_ack     : in std_ulogic;
+        dbg_spr_addr    : out std_ulogic_vector(7 downto 0);
+        dbg_spr_data    : in std_ulogic_vector(63 downto 0);
+
         -- Core logging data
         log_data        : in std_ulogic_vector(255 downto 0);
         log_read_addr   : in std_ulogic_vector(31 downto 0);
@@ -105,7 +111,10 @@ architecture behave of core_debug is
     signal do_icreset   : std_ulogic;
     signal terminated   : std_ulogic;
     signal do_gspr_rd   : std_ulogic;
-    signal gspr_index   : gspr_index_t;
+    signal gspr_index   : std_ulogic_vector(7 downto 0);
+    signal gspr_data    : std_ulogic_vector(63 downto 0);
+
+    signal spr_index_valid : std_ulogic;
 
     signal log_dmi_addr        : std_ulogic_vector(31 downto 0) := (others => '0');
     signal log_dmi_data        : std_ulogic_vector(63 downto 0) := (others => '0');
@@ -119,9 +128,7 @@ architecture behave of core_debug is
 begin
        -- Single cycle register accesses on DMI except for GSPR data
     dmi_ack <= dmi_req when dmi_addr /= DBG_CORE_GSPR_DATA
-               else dbg_gpr_ack;
-    dbg_gpr_req <= dmi_req when dmi_addr = DBG_CORE_GSPR_DATA
-                   else '0';
+               else dbg_gpr_ack or dbg_spr_ack;
 
     -- Status register read composition
     stat_reg <= (2 => terminated,
@@ -129,12 +136,16 @@ begin
                  0 => stopping,
                  others => '0');
 
+    gspr_data <= dbg_gpr_data when gspr_index(5) = '0' else
+                 dbg_spr_data when spr_index_valid = '1' else
+                 (others => '0');
+
     -- DMI read data mux
     with dmi_addr select dmi_dout <=
         stat_reg        when DBG_CORE_STAT,
         nia             when DBG_CORE_NIA,
         msr             when DBG_CORE_MSR,
-        dbg_gpr_data    when DBG_CORE_GSPR_DATA,
+        gspr_data       when DBG_CORE_GSPR_DATA,
         log_write_addr & log_dmi_addr when DBG_CORE_LOG_ADDR,
         log_dmi_data    when DBG_CORE_LOG_DATA,
         log_dmi_trigger when DBG_CORE_LOG_TRIGGER,
@@ -191,7 +202,7 @@ begin
                                 terminated <= '0';
                             end if;
                         elsif dmi_addr = DBG_CORE_GSPR_INDEX then
-                            gspr_index <= dmi_din(gspr_index_t'left downto 0);
+                            gspr_index <= dmi_din(7 downto 0);
                         elsif dmi_addr = DBG_CORE_LOG_ADDR then
                             log_dmi_addr <= dmi_din(31 downto 0);
                             do_dmi_log_rd <= '1';
@@ -226,7 +237,64 @@ begin
         end if;
     end process;
 
-    dbg_gpr_addr <= gspr_index;
+    gspr_access: process(clk)
+        variable valid : std_ulogic;
+        variable sel : spr_selector;
+        variable isram : std_ulogic;
+        variable raddr : ramspr_index;
+        variable odd : std_ulogic;
+    begin
+        if rising_edge(clk) then
+            if rst = '1' or dmi_req = '0' or dmi_addr /= DBG_CORE_GSPR_DATA then
+                dbg_gpr_req <= '0';
+                dbg_spr_req <= '0';
+            else
+                dbg_gpr_req <= not gspr_index(5);
+                dbg_spr_req <= gspr_index(5);
+            end if;
+
+            -- Map 0 - 0x1f to GPRs, 0x20 - 0x3f to SPRs, and 0x40 - 0x5f to FPRs
+            dbg_gpr_addr <= gspr_index(6) & gspr_index(4 downto 0);
+
+            -- For SPRs, use the same mapping as when the fast SPRs were in the GPR file
+            valid := '1';
+            sel := "000";
+            isram := '1';
+            raddr := 0;
+            odd := '0';
+            case gspr_index(4 downto 0) is
+                when 5x"00" =>
+                    raddr := RAMSPR_LR;
+                when 5x"01" =>
+                    odd := '1';
+                    raddr := RAMSPR_CTR;
+                when 5x"02" | 5x"03" =>
+                    odd := gspr_index(0);
+                    raddr := RAMSPR_SRR0;
+                when 5x"04" | 5x"05" =>
+                    odd := gspr_index(0);
+                    raddr := RAMSPR_HSRR0;
+                when 5x"06" | 5x"07" =>
+                    odd := gspr_index(0);
+                    raddr := RAMSPR_SPRG0;
+                when 5x"08" | 5x"09" =>
+                    odd := gspr_index(0);
+                    raddr := RAMSPR_SPRG2;
+                when 5x"0a" | 5x"0b" =>
+                    odd := gspr_index(0);
+                    raddr := RAMSPR_HSPRG0;
+                when 5x"0c" =>
+                    isram := '0';
+                    sel := SPRSEL_XER;
+                when 5x"0d" =>
+                    raddr := RAMSPR_TAR;
+                when others =>
+                    valid := '0';
+            end case;
+            dbg_spr_addr <= isram & sel & std_ulogic_vector(to_unsigned(raddr, 3)) & odd;
+            spr_index_valid <= valid;
+        end if;
+    end process;
 
     -- Core control signals generated by the debug module
     core_stop <= stopping and not do_step;
index 5a8c2b733718a3e7421eb20c368dd6be4f333087..d91bec55ab15b53bf04c93473ab68b51f7893edb 100644 (file)
@@ -43,6 +43,10 @@ entity decode2 is
         execute2_cr_bypass : in cr_bypass_data_t;
         writeback_bypass  : in bypass_data_t;
 
+        -- Access to SPRs from core_debug module
+        dbg_spr_req  : in std_ulogic;
+        dbg_spr_addr : in std_ulogic_vector(7 downto 0);
+
         log_out : out std_ulogic_vector(9 downto 0)
        );
 end entity decode2;
@@ -60,6 +64,7 @@ architecture behaviour of decode2 is
         reg_o_valid : std_ulogic;
         input_ov  : std_ulogic;
         output_ov : std_ulogic;
+        read_rspr : std_ulogic;
     end record;
     constant reg_type_init : reg_type :=
         (e => Decode2ToExecute1Init, repeat => NONE, others => '0');
@@ -347,6 +352,13 @@ begin
                         " tag=" & integer'image(dc2in.e.instr_tag.tag) & std_ulogic'image(dc2in.e.instr_tag.valid);
                 end if;
                 dc2 <= dc2in;
+            elsif dc2.read_rspr = '0' then
+                -- Update debug SPR access signals even when stalled
+                -- if the instruction in dc2.e doesn't read any SPRs.
+                dc2.e.dbg_spr_access <= dc2in.e.dbg_spr_access;
+                dc2.e.ramspr_even_rdaddr <= dc2in.e.ramspr_even_rdaddr;
+                dc2.e.ramspr_odd_rdaddr <= dc2in.e.ramspr_odd_rdaddr;
+                dc2.e.ramspr_rd_odd <= dc2in.e.ramspr_rd_odd;
             end if;
         end if;
     end process;
@@ -381,6 +393,7 @@ begin
         variable op : insn_type_t;
         variable valid_in : std_ulogic;
         variable decctr : std_ulogic;
+        variable sprs_busy : std_ulogic;
     begin
         v := dc2;
 
@@ -389,6 +402,8 @@ begin
         if dc2.busy = '0' then
             v.e := Decode2ToExecute1Init;
 
+            sprs_busy := '0';
+
             if d_in.valid = '1' then
                 v.prev_sgl := dc2.sgl_pipe;
                 v.sgl_pipe := d_in.decode.sgl_pipe;
@@ -467,6 +482,7 @@ begin
                 v.e.ramspr_odd_rdaddr := RAMSPR_CTR;
                 v.e.ramspr_wraddr := RAMSPR_CTR;
                 v.e.ramspr_write_odd := '1';
+                sprs_busy := '1';
             end if;
             if v.e.lr = '1' then
                 -- write LR
@@ -484,11 +500,13 @@ begin
                     else
                         v.e.ramspr_even_rdaddr := RAMSPR_TAR;
                     end if;
+                    sprs_busy := '1';
                 when OP_MFSPR =>
                     v.e.ramspr_even_rdaddr := d_in.ram_spr.index;
                     v.e.ramspr_odd_rdaddr := d_in.ram_spr.index;
                     v.e.ramspr_rd_odd := d_in.ram_spr.isodd;
                     v.e.spr_is_ram := d_in.ram_spr.valid;
+                    sprs_busy := d_in.ram_spr.valid;
                 when OP_MTSPR =>
                     v.e.ramspr_wraddr := d_in.ram_spr.index;
                     v.e.ramspr_write_even := d_in.ram_spr.valid and not d_in.ram_spr.isodd;
@@ -497,8 +515,10 @@ begin
                 when OP_RFID =>
                     v.e.ramspr_even_rdaddr := RAMSPR_SRR0;
                     v.e.ramspr_odd_rdaddr := RAMSPR_SRR1;
+                    sprs_busy := '1';
                 when others =>
             end case;
+            v.read_rspr := sprs_busy and d_in.valid;
 
             case d_in.decode.length is
                 when is1B =>
@@ -545,8 +565,6 @@ begin
                     -- Privileged mfspr to invalid/unimplemented SPR numbers
                     -- writes the contents of RT back to RT (i.e. it's a no-op)
                     v.e.result_sel := "001";        -- logical_result
-                elsif d_in.spr_info.ispmu = '1' then
-                    v.e.result_sel := "100";        -- pmuspr_result
                 end if;
             end if;
 
@@ -649,6 +667,13 @@ begin
 
         stall_out <= dc2.busy or deferred;
 
+        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_rd_odd := dbg_spr_addr(0);
+        end if;
+
         -- Update registers
         dc2in <= v;
 
index dc68806cbd2ef73ebdb867023202a9a2a233bf40..20efef61796eccff39164c25add0c88a3c138962 100644 (file)
@@ -55,6 +55,12 @@ entity execute1 is
         dc_events    : in DcacheEventType;
         ic_events    : in IcacheEventType;
 
+        -- Access to SPRs from core_debug module
+        dbg_spr_req   : in std_ulogic;
+        dbg_spr_ack   : out std_ulogic;
+        dbg_spr_addr  : in std_ulogic_vector(7 downto 0);
+        dbg_spr_data  : out std_ulogic_vector(63 downto 0);
+
         -- debug
         sim_dump      : in std_ulogic;
         sim_dump_done : out std_ulogic;
@@ -604,6 +610,24 @@ begin
        end if;
     end process;
 
+    ex_dbg_spr: process(clk)
+    begin
+        if rising_edge(clk) then
+            if rst = '0' and dbg_spr_req = '1' then
+                if e_in.dbg_spr_access = '1' and dbg_spr_ack = '0' then
+                    if dbg_spr_addr(7) = '1' then
+                        dbg_spr_data <= ramspr_result;
+                    else
+                        dbg_spr_data <= assemble_xer(xerc_in, ctrl.xer_low);
+                    end if;
+                    dbg_spr_ack <= '1';
+                end if;
+            else
+                dbg_spr_ack <= '0';
+            end if;
+        end if;
+    end process;
+
     -- Data path for integer instructions (first execute stage)
     execute1_dp: process(all)
        variable a_inv : std_ulogic_vector(63 downto 0);
index 62717601a2d481eda60bb255f10f5acf49255c2a..ef5b1ec2e9ce366a357462916805c4c1b397aa76 100644 (file)
@@ -548,7 +548,7 @@ static const char *fast_spr_names[] =
 {
        "lr", "ctr", "srr0", "srr1", "hsrr0", "hsrr1",
        "sprg0", "sprg1", "sprg2", "sprg3",
-       "hsprg0", "hsprg1", "xer"
+       "hsprg0", "hsprg1", "xer", "tar",
 };
 
 static void gpr_read(uint64_t reg, uint64_t count)