debug: Provide a way to examine GPRs, fast SPRs and MSR
authorPaul Mackerras <paulus@ozlabs.org>
Sat, 2 May 2020 03:26:30 +0000 (13:26 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 8 May 2020 02:12:01 +0000 (12:12 +1000)
This provides commands on the debug interface to read the value of
the MSR or any of the 64 GSPR register file entries.  The GSPR values
are read using the B port of the register file in a cycle when
decode2 is not using it.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
core.vhdl
core_debug.vhdl
decode2.vhdl
execute1.vhdl
register_file.vhdl

index 0e6090546a9332dbb9857f690be3ee19068b15a2..acb37cc83bf0786d9741da82263e711c4cb927fc 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -95,6 +95,13 @@ architecture behave of core is
     signal dbg_core_rst: std_ulogic;
     signal dbg_icache_rst: std_ulogic;
 
+    signal dbg_gpr_req : std_ulogic;
+    signal dbg_gpr_ack : std_ulogic;
+    signal dbg_gpr_addr : gspr_index_t;
+    signal dbg_gpr_data : std_ulogic_vector(63 downto 0);
+
+    signal msr : std_ulogic_vector(63 downto 0);
+
     -- Debug status
     signal dbg_core_is_stopped: std_ulogic;
 
@@ -213,6 +220,10 @@ begin
             d_in => decode2_to_register_file,
             d_out => register_file_to_decode2,
             w_in => writeback_to_register_file,
+            dbg_gpr_req => dbg_gpr_req,
+            dbg_gpr_ack => dbg_gpr_ack,
+            dbg_gpr_addr => dbg_gpr_addr,
+            dbg_gpr_data => dbg_gpr_data,
            sim_dump => terminate,
            sim_dump_done => sim_cr_dump
            );
@@ -244,6 +255,7 @@ begin
             f_out => execute1_to_fetch1,
             e_out => execute1_to_writeback,
            icache_inval => ex1_icache_inval,
+            dbg_msr_out => msr,
             terminate_out => terminate
             );
 
@@ -301,6 +313,11 @@ begin
            terminate => terminate,
            core_stopped => dbg_core_is_stopped,
            nia => fetch1_to_icache.nia,
+            msr => msr,
+            dbg_gpr_req => dbg_gpr_req,
+            dbg_gpr_ack => dbg_gpr_ack,
+            dbg_gpr_addr => dbg_gpr_addr,
+            dbg_gpr_data => dbg_gpr_data,
            terminated_out => terminated_out
            );
 
index ae4414e15704be9864c5521a5255bde8dd51d81d..c97213be49f6cc7588dd939e43cf82454864a1d6 100644 (file)
@@ -26,6 +26,13 @@ entity core_debug is
        terminate       : in std_ulogic;
        core_stopped    : in std_ulogic;
        nia             : in std_ulogic_vector(63 downto 0);
+        msr             : in std_ulogic_vector(63 downto 0);
+
+        -- GSPR 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);
 
        -- Misc
        terminated_out  : out std_ulogic
@@ -61,6 +68,15 @@ architecture behave of core_debug is
     -- NIA register (read only for now)
     constant DBG_CORE_NIA           : std_ulogic_vector(3 downto 0) := "0010";
 
+    -- MSR (read only)
+    constant DBG_CORE_MSR            : std_ulogic_vector(3 downto 0) := "0011";
+
+    -- GSPR register index
+    constant DBG_CORE_GSPR_INDEX     : std_ulogic_vector(3 downto 0) := "0100";
+
+    -- GSPR register data
+    constant DBG_CORE_GSPR_DATA      : std_ulogic_vector(3 downto 0) := "0101";
+
     -- Some internal wires
     signal stat_reg : std_ulogic_vector(63 downto 0);
 
@@ -70,10 +86,15 @@ architecture behave of core_debug is
     signal do_reset     : std_ulogic;
     signal do_icreset   : std_ulogic;
     signal terminated   : std_ulogic;
+    signal do_gspr_rd   : std_ulogic;
+    signal gspr_index   : gspr_index_t;
 
 begin
-       -- Single cycle register accesses on DMI
-    dmi_ack <= dmi_req;
+       -- 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';
 
     -- Status register read composition
     stat_reg <= (2 => terminated,
@@ -85,6 +106,8 @@ begin
     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,
        (others => '0') when others;
 
     -- DMI writes
@@ -126,6 +149,8 @@ begin
                                stopping <= '0';
                                terminated <= '0';
                            end if;
+                        elsif dmi_addr = DBG_CORE_GSPR_INDEX then
+                            gspr_index <= dmi_din(gspr_index_t'left downto 0);
                        end if;
                    else
                        report("DMI read from " & to_string(dmi_addr));
@@ -143,6 +168,8 @@ begin
        end if;
     end process;
 
+    dbg_gpr_addr <= gspr_index;
+
     -- Core control signals generated by the debug module
     core_stop <= stopping and not do_step;
     core_rst <= do_reset;
index edcc50cff97f1aab11037727478446e70430d588..b23939299e240ca8bfcc46d8ad29b97ba1a1c1ba 100644 (file)
@@ -285,9 +285,9 @@ begin
                decoded_reg_c := decode_input_reg_c (d_in.decode.input_reg_c, d_in.insn, r_in.read3_data);
                decoded_reg_o := decode_output_reg (d_in.decode.output_reg_a, d_in.insn, d_in.ispr1);
 
-               r_out.read1_enable <= decoded_reg_a.reg_valid;
-               r_out.read2_enable <= decoded_reg_b.reg_valid;
-               r_out.read3_enable <= decoded_reg_c.reg_valid;
+               r_out.read1_enable <= decoded_reg_a.reg_valid and d_in.valid;
+               r_out.read2_enable <= decoded_reg_b.reg_valid and d_in.valid;
+               r_out.read3_enable <= decoded_reg_c.reg_valid and d_in.valid;
 
                case d_in.decode.length is
                when is1B =>
index c479a451f469e359d2eb23a0d53acd188be00b29..82776e2d78561f8e6311a8e6fbddcca2ba65a254 100644 (file)
@@ -32,6 +32,8 @@ entity execute1 is
 
        e_out : out Execute1ToWritebackType;
 
+        dbg_msr_out : out std_ulogic_vector(63 downto 0);
+
        icache_inval : out std_ulogic;
        terminate_out : out std_ulogic
        );
@@ -217,6 +219,8 @@ begin
             d_out => divider_to_x
             );
 
+    dbg_msr_out <= ctrl.msr;
+
     a_in <= r.e.write_data when EX1_BYPASS and e_in.bypass_data1 = '1' else e_in.read_data1;
     b_in <= r.e.write_data when EX1_BYPASS and e_in.bypass_data2 = '1' else e_in.read_data2;
     c_in <= r.e.write_data when EX1_BYPASS and e_in.bypass_data3 = '1' else e_in.read_data3;
index 6a4c9899df992b613c47478f490dcd2253237b97..2cffeea2511aedbbc9aca93c8efd6b125ad47928 100644 (file)
@@ -17,6 +17,11 @@ entity register_file is
 
         w_in          : in WritebackToRegisterFileType;
 
+        dbg_gpr_req   : in std_ulogic;
+        dbg_gpr_ack   : out std_ulogic;
+        dbg_gpr_addr  : in gspr_index_t;
+        dbg_gpr_data  : out std_ulogic_vector(63 downto 0);
+
         -- debug
         sim_dump      : in std_ulogic;
         sim_dump_done : out std_ulogic
@@ -26,6 +31,9 @@ end entity register_file;
 architecture behaviour of register_file is
     type regfile is array(0 to 63) of std_ulogic_vector(63 downto 0);
     signal registers : regfile := (others => (others => '0'));
+    signal rd_port_b : std_ulogic_vector(63 downto 0);
+    signal dbg_data : std_ulogic_vector(63 downto 0);
+    signal dbg_ack : std_ulogic;
 begin
     -- synchronous writes
     register_write_0: process(clk)
@@ -45,6 +53,7 @@ begin
 
     -- asynchronous reads
     register_read_0: process(all)
+        variable b_addr : gspr_index_t;
     begin
         if d_in.read1_enable = '1' then
             report "Reading GPR " & to_hstring(d_in.read1_reg) & " " & to_hstring(registers(to_integer(unsigned(d_in.read1_reg))));
@@ -56,7 +65,14 @@ begin
             report "Reading GPR " & to_hstring(d_in.read3_reg) & " " & to_hstring(registers(to_integer(unsigned(d_in.read3_reg))));
         end if;
         d_out.read1_data <= registers(to_integer(unsigned(d_in.read1_reg)));
-        d_out.read2_data <= registers(to_integer(unsigned(d_in.read2_reg)));
+        -- B read port is multiplexed with reads from the debug circuitry
+        if d_in.read2_enable = '0' and dbg_gpr_req = '1' and dbg_ack = '0' then
+            b_addr := dbg_gpr_addr;
+        else
+            b_addr := d_in.read2_reg;
+        end if;
+        rd_port_b <= registers(to_integer(unsigned(b_addr)));
+        d_out.read2_data <= rd_port_b;
         d_out.read3_data <= registers(to_integer(unsigned(gpr_to_gspr(d_in.read3_reg))));
 
         -- Forward any written data
@@ -73,6 +89,24 @@ begin
         end if;
     end process register_read_0;
 
+    -- Latch read data and ack if dbg read requested and B port not busy
+    dbg_register_read: process(clk)
+    begin
+        if rising_edge(clk) then
+            if dbg_gpr_req = '1' then
+                if d_in.read2_enable = '0' and dbg_ack = '0' then
+                    dbg_data <= rd_port_b;
+                    dbg_ack <= '1';
+                end if;
+            else
+                dbg_ack <= '0';
+            end if;
+        end if;
+    end process;
+
+    dbg_gpr_ack <= dbg_ack;
+    dbg_gpr_data <= dbg_data;
+
     -- Dump registers if core terminates
     sim_dump_test: if SIM generate
        dump_registers: process(all)