Provide debug access to SPRs in loadstore1 and mmu
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 24 Feb 2022 00:37:17 +0000 (11:37 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 22 Jul 2022 12:20:45 +0000 (22:20 +1000)
They are accessible as GSPR 0x3c - PID, 0x3d - PTCR, 0x3e - DSISR
and 0x3f - DAR.

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

index d743c2d5b5a2754f2417c4d246810dce1ff1ef17..39ebfb1ba1d47341e88ba9110639d73148bb7043 100644 (file)
@@ -547,7 +547,9 @@ package common is
         iside : std_ulogic;
         load  : std_ulogic;
         priv  : std_ulogic;
-        sprn  : std_ulogic_vector(9 downto 0);
+        ric   : std_ulogic_vector(1 downto 0);
+        sprnf : std_ulogic;
+        sprnt : std_ulogic;
         addr  : std_ulogic_vector(63 downto 0);
         rs    : std_ulogic_vector(63 downto 0);
     end record;
index a91b72983f064b117d125aa47aeafd3cb18c2aaf..641c12d16dcc4a419efe1efcf448b29ce6f44bac 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -154,6 +154,10 @@ architecture behave of core is
     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 dbg_ls_spr_req : std_ulogic;
+    signal dbg_ls_spr_ack : std_ulogic;
+    signal dbg_ls_spr_addr : std_ulogic_vector(1 downto 0);
+    signal dbg_ls_spr_data : std_ulogic_vector(63 downto 0);
 
     signal ctrl_debug : ctrl_t;
 
@@ -432,6 +436,10 @@ begin
             m_in => mmu_to_loadstore1,
             dc_stall => dcache_stall_out,
             events => loadstore_events,
+            dbg_spr_req => dbg_ls_spr_req,
+            dbg_spr_ack => dbg_ls_spr_ack,
+            dbg_spr_addr => dbg_ls_spr_addr,
+            dbg_spr_data => dbg_ls_spr_data,
             log_out => log_data(149 downto 140)
             );
 
@@ -518,6 +526,10 @@ begin
             dbg_spr_ack => dbg_spr_ack,
             dbg_spr_addr => dbg_spr_addr,
             dbg_spr_data => dbg_spr_data,
+            dbg_ls_spr_req => dbg_ls_spr_req,
+            dbg_ls_spr_ack => dbg_ls_spr_ack,
+            dbg_ls_spr_addr => dbg_ls_spr_addr,
+            dbg_ls_spr_data => dbg_ls_spr_data,
             log_data => log_data,
             log_read_addr => log_rd_addr,
             log_read_data => log_rd_data,
index a1d4a942b697f18c8e54b0de66ec2130422db7b6..c060f745f169e5140a39560874a93490b1016143 100644 (file)
@@ -39,12 +39,18 @@ entity core_debug is
         dbg_gpr_addr    : out gspr_index_t;
         dbg_gpr_data    : in std_ulogic_vector(63 downto 0);
 
-        -- SPR register read port
+        -- SPR register read port for SPRs in execute1
         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);
 
+        -- SPR register read port for SPRs in loadstore1 and mmu
+        dbg_ls_spr_req  : out std_ulogic;
+        dbg_ls_spr_ack  : in std_ulogic;
+        dbg_ls_spr_addr : out std_ulogic_vector(1 downto 0);
+        dbg_ls_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);
@@ -128,7 +134,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 or dbg_spr_ack;
+               else dbg_gpr_ack or dbg_spr_ack or dbg_ls_spr_ack;
 
     -- Status register read composition
     stat_reg <= (2 => terminated,
@@ -137,6 +143,7 @@ begin
                  others => '0');
 
     gspr_data <= dbg_gpr_data when gspr_index(5) = '0' else
+                 dbg_ls_spr_data when dbg_ls_spr_req = '1' else
                  dbg_spr_data when spr_index_valid = '1' else
                  (others => '0');
 
@@ -245,16 +252,22 @@ begin
         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);
+            dbg_gpr_req <= '0';
+            dbg_spr_req <= '0';
+            dbg_ls_spr_req <= '0';
+            if rst = '0' and dmi_req = '1' and dmi_addr = DBG_CORE_GSPR_DATA then
+                if gspr_index(5) = '0' then
+                    dbg_gpr_req <= '1';
+                elsif gspr_index(4 downto 2) = "111" then
+                    dbg_ls_spr_req <= '1';
+                else
+                    dbg_spr_req <= '1';
+                end if;
             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);
+            dbg_ls_spr_addr <= gspr_index(1 downto 0);
 
             -- For SPRs, use the same mapping as when the fast SPRs were in the GPR file
             valid := '1';
index 9dab15bbe23ffad5e37b5af33eee025c311e00a8..92ebeec1f0e024b9de43209256e80edbb4c7ba81 100644 (file)
@@ -35,6 +35,12 @@ entity loadstore1 is
 
         events  : out Loadstore1EventType;
 
+        -- 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(1 downto 0);
+        dbg_spr_data  : out std_ulogic_vector(63 downto 0);
+
         log_out : out std_ulogic_vector(9 downto 0)
         );
 end loadstore1;
@@ -123,6 +129,8 @@ architecture behave of loadstore1 is
         one_cycle  : std_ulogic;
         wr_sel     : std_ulogic_vector(1 downto 0);
         addr0      : std_ulogic_vector(63 downto 0);
+        sprsel     : std_ulogic_vector(1 downto 0);
+        dbg_spr_rd : std_ulogic;
     end record;
 
     type reg_stage3_t is record
@@ -146,6 +154,8 @@ architecture behave of loadstore1 is
         intr_vec     : integer range 0 to 16#fff#;
         srr1         : std_ulogic_vector(15 downto 0);
         events       : Loadstore1EventType;
+        dbg_spr      : std_ulogic_vector(63 downto 0);
+        dbg_spr_ack  : std_ulogic;
     end record;
 
     signal req_in   : request_t;
@@ -664,6 +674,20 @@ begin
             v.busy := '1';
         end if;
 
+        v.dbg_spr_rd := dbg_spr_req and not (v.req.valid and v.req.read_spr);
+        if v.dbg_spr_rd = '0' then
+            v.sprsel(1) := v.req.sprn(1);
+            if v.req.sprn(1) = '1' then
+                -- DSISR and DAR
+                v.sprsel(0) := v.req.sprn(0);
+            else
+                -- PID and PTCR
+                v.sprsel(0) := v.req.sprn(8);
+            end if;
+        else
+            v.sprsel := dbg_spr_addr;
+        end if;
+
         r2in <= v;
     end process;
 
@@ -763,21 +787,26 @@ begin
             v.load_data := data_permuted;
         end if;
 
+        -- SPR mux
+        if r2.sprsel(1) = '1' then
+            if r2.sprsel(0) = '0' then
+                sprval := x"00000000" & r3.dsisr;
+            else
+                sprval := r3.dar;
+            end if;
+        else
+            sprval := m_in.sprval;
+        end if;
+        if dbg_spr_req = '0' then
+            v.dbg_spr_ack := '0';
+        elsif r2.dbg_spr_rd = '1' and r3.dbg_spr_ack = '0' then
+            v.dbg_spr := sprval;
+            v.dbg_spr_ack := '1';
+        end if;
+
         if r2.req.valid = '1' then
             if r2.req.read_spr = '1' then
                 write_enable := '1';
-                -- partial decode on SPR number should be adequate given
-                -- the restricted set that get sent down this path
-                if r2.req.sprn(8) = '0' and r2.req.sprn(5) = '0' then
-                    if r2.req.sprn(0) = '0' then
-                        sprval := x"00000000" & r3.dsisr;
-                    else
-                        sprval := r3.dar;
-                    end if;
-                else
-                    -- reading one of the SPRs in the MMU
-                    sprval := m_in.sprval;
-                end if;
             end if;
             if r2.req.align_intr = '1' then
                 -- generate alignment interrupt
@@ -940,8 +969,10 @@ begin
         m_out.load <= r2.req.load;
         m_out.priv <= r2.req.priv_mode;
         m_out.tlbie <= r2.req.tlbie;
+        m_out.ric <= r2.req.sprn(3 downto 2);
         m_out.mtspr <= mmu_mtspr;
-        m_out.sprn <= r2.req.sprn;
+        m_out.sprnf <= r2.sprsel(0);
+        m_out.sprnt <= r2.req.sprn(8);
         m_out.addr <= r2.req.addr;
         m_out.slbia <= r2.req.is_slbia;
         m_out.rs <= r2.req.store_data;
@@ -967,6 +998,10 @@ begin
 
         flush <= exception;
 
+        -- SPR values for core_debug
+        dbg_spr_data <= r3.dbg_spr;
+        dbg_spr_ack <= r3.dbg_spr_ack;
+
         -- Update registers
         r3in <= v;
 
index d80caf449ce8a00bbc80ab25d97736e7c123ae7b..d95cd3cc3eba1b261489d82112dfd368534b5d99 100644 (file)
--- a/mmu.vhdl
+++ b/mmu.vhdl
@@ -81,8 +81,8 @@ architecture behave of mmu is
 
 begin
     -- Multiplex internal SPR values back to loadstore1, selected
-    -- by l_in.sprn.
-    l_out.sprval <= r.ptcr when l_in.sprn(8) = '1' else x"00000000" & r.pid;
+    -- by l_in.sprnf.
+    l_out.sprval <= r.ptcr when l_in.sprnf = '1' else x"00000000" & r.pid;
 
     mmu_0: process(clk)
     begin
@@ -259,9 +259,8 @@ begin
                     -- RB[IS] != 0 or RB[AP] != 0, or for slbia
                     v.inval_all := l_in.slbia or l_in.addr(11) or l_in.addr(10) or
                                    l_in.addr(7) or l_in.addr(6) or l_in.addr(5);
-                    -- The RIC field of the tlbie instruction comes across on the
-                    -- sprn bus as bits 2--3.  RIC=2 flushes process table caches.
-                    if l_in.sprn(3) = '1' then
+                    -- RIC=2 or 3 flushes process table caches.
+                    if l_in.ric(1) = '1' then
                         v.pt0_valid := '0';
                         v.pt3_valid := '0';
                         v.ptb_valid := '0';
@@ -291,7 +290,7 @@ begin
                 -- Move to PID needs to invalidate L1 TLBs and cached
                 -- pgtbl0 value.  Move to PTCR does that plus
                 -- invalidating the cached pgtbl3 and prtbl values as well.
-                if l_in.sprn(8) = '0' then
+                if l_in.sprnt = '0' then
                     v.pid := l_in.rs(31 downto 0);
                 else
                     v.ptcr := l_in.rs;
index ef5b1ec2e9ce366a357462916805c4c1b397aa76..81e80941609bab183fb307b61ee21cc78fa8f3fd 100644 (file)
@@ -551,6 +551,10 @@ static const char *fast_spr_names[] =
        "hsprg0", "hsprg1", "xer", "tar",
 };
 
+static const char *ldst_spr_names[] = {
+       "pidr", "ptcr", "dsisr", "dar"
+};
+
 static void gpr_read(uint64_t reg, uint64_t count)
 {
        uint64_t data;
@@ -566,8 +570,10 @@ static void gpr_read(uint64_t reg, uint64_t count)
                        printf("r%"PRId64, reg);
                else if ((reg - 32) < sizeof(fast_spr_names) / sizeof(fast_spr_names[0]))
                        printf("%s", fast_spr_names[reg - 32]);
-               else if (reg < 64)
+               else if (reg < 60)
                        printf("gspr%"PRId64, reg);
+               else if (reg < 64)
+                       printf("%s", ldst_spr_names[reg - 60]);
                else
                        printf("FPR%"PRId64, reg - 64);
                printf(":\t%016"PRIx64"\n", data);