diff --git a/example_soc/soc/example_soc.v b/example_soc/soc/example_soc.v index a294612..729f732 100644 --- a/example_soc/soc/example_soc.v +++ b/example_soc/soc/example_soc.v @@ -1,5 +1,5 @@ /*****************************************************************************\ -| Copyright (C) 2021 Luke Wren | +| Copyright (C) 2021-2022 Luke Wren | | SPDX-License-Identifier: Apache-2.0 | \*****************************************************************************/ @@ -141,8 +141,18 @@ wire [N_HARTS-1:0] hart_instr_data_rdy; wire [N_HARTS-1:0] hart_instr_caught_exception; wire [N_HARTS-1:0] hart_instr_caught_ebreak; +wire [31:0] sbus_addr; +wire sbus_write; +wire [1:0] sbus_size; +wire sbus_vld; +wire sbus_rdy; +wire sbus_err; +wire [31:0] sbus_wdata; +wire [31:0] sbus_rdata; + hazard3_dm #( .N_HARTS (N_HARTS), + .HAVE_SBA (0), .NEXT_DM_ADDR (0) ) dm ( .clk (clk), @@ -176,7 +186,16 @@ hazard3_dm #( .hart_instr_data_vld (hart_instr_data_vld), .hart_instr_data_rdy (hart_instr_data_rdy), .hart_instr_caught_exception (hart_instr_caught_exception), - .hart_instr_caught_ebreak (hart_instr_caught_ebreak) + .hart_instr_caught_ebreak (hart_instr_caught_ebreak), + + .sbus_addr (sbus_addr), + .sbus_write (sbus_write), + .sbus_size (sbus_size), + .sbus_vld (sbus_vld), + .sbus_rdy (sbus_rdy), + .sbus_err (sbus_err), + .sbus_wdata (sbus_wdata), + .sbus_rdata (sbus_rdata) ); @@ -279,6 +298,15 @@ hazard3_cpu_1port #( .dbg_instr_caught_exception (hart_instr_caught_exception), .dbg_instr_caught_ebreak (hart_instr_caught_ebreak), + .dbg_sbus_addr (sbus_addr), + .dbg_sbus_write (sbus_write), + .dbg_sbus_size (sbus_size), + .dbg_sbus_vld (sbus_vld), + .dbg_sbus_rdy (sbus_rdy), + .dbg_sbus_err (sbus_err), + .dbg_sbus_wdata (sbus_wdata), + .dbg_sbus_rdata (sbus_rdata), + .irq (uart_irq), .soft_irq (1'b0), diff --git a/hdl/hazard3_cpu_1port.v b/hdl/hazard3_cpu_1port.v index 10c5ea7..7165b3d 100644 --- a/hdl/hazard3_cpu_1port.v +++ b/hdl/hazard3_cpu_1port.v @@ -52,6 +52,16 @@ module hazard3_cpu_1port #( output wire dbg_instr_caught_exception, output wire dbg_instr_caught_ebreak, + // Optional debug system bus access patch-through + input wire [W_ADDR-1:0] dbg_sbus_addr, + input wire dbg_sbus_write, + input wire [1:0] dbg_sbus_size, + input wire dbg_sbus_vld, + output wire dbg_sbus_rdy, + output wire dbg_sbus_err, + input wire [W_DATA-1:0] dbg_sbus_wdata, + output wire [W_DATA-1:0] dbg_sbus_rdata, + // Level-sensitive interrupt sources input wire [NUM_IRQ-1:0] irq, // -> mip.meip input wire soft_irq, // -> mip.msip @@ -137,6 +147,8 @@ hazard3_core #( .dbg_instr_caught_exception (dbg_instr_caught_exception), .dbg_instr_caught_ebreak (dbg_instr_caught_ebreak), + + .irq (irq), .soft_irq (soft_irq), .timer_irq (timer_irq) @@ -147,28 +159,42 @@ hazard3_core #( wire bus_gnt_i; wire bus_gnt_d; +wire bus_gnt_s; reg bus_hold_aph; -reg [1:0] bus_gnt_id_prev; +reg [2:0] bus_gnt_ids_prev; always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin bus_hold_aph <= 1'b0; - bus_gnt_id_prev <= 2'h0; + bus_gnt_id_prev <= 3'h0; end else begin bus_hold_aph <= ahblm_htrans[1] && !ahblm_hready && !ahblm_hresp; - bus_gnt_id_prev <= {bus_gnt_i, bus_gnt_d}; + bus_gnt_id_prev <= {bus_gnt_i, bus_gnt_d, bus_gnt_s}; end end -assign {bus_gnt_i, bus_gnt_d} = - bus_hold_aph ? bus_gnt_id_prev : - core_aph_panic_i ? 2'b10 : - core_aph_req_d ? 2'b01 : - core_aph_req_i ? 2'b10 : - 2'b00 ; +// Debug SBA access is lower priority than load/store, but higher than +// instruction fetch. This isn't ideal, but in a tight loop the core may be +// performing an instruction fetch or load/store on every single cycle, and +// this is a simple way to guarantee eventual success of debugger accesses. A +// more complex way would be to add a "panic timer" to boost a stalled sbus +// access over an instruction fetch. -// Keep track of whether instr/data access is active in AHB dataphase. +// Note that, often, the sbus will be disconnected: it doesn't provide any +// increase in debugger bus throughput compared with the program buffer and +// autoexec. It's useful for "minimally intrusive" debug bus access(i.e. less +// intrusive than halting the core and resuming it) e.g. for Segger RTT. + +reg bus_active_dph_s; + +assign {bus_gnt_i, bus_gnt_d, bus_gnt_s} = + bus_hold_aph ? bus_gnt_id_prev : + core_aph_panic_i ? 3'b100 : + core_aph_req_d ? 3'b010 : + dbg_sbus_vld && !bus_active_dph_s ? 3'b001 : + core_aph_req_i ? 3'b100 : + 3'b000 ; reg bus_active_dph_i; reg bus_active_dph_d; @@ -176,9 +202,11 @@ always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin bus_active_dph_i <= 1'b0; bus_active_dph_d <= 1'b0; + bus_active_dph_s <= 1'b0; end else if (ahblm_hready) begin bus_active_dph_i <= bus_gnt_i; bus_active_dph_d <= bus_gnt_d; + bus_active_dph_s <= bus_gnt_s; end end @@ -200,11 +228,24 @@ wire [3:0] hprot_instr = { 1'b0 // Instruction access }; +wire [3:0] hprot_sbus = { + 2'b00, // Noncacheable/nonbufferable + 1'b1, // Always privileged + 1'b1 // Data access +}; + assign ahblm_hburst = 3'b000; // HBURST_SINGLE assign ahblm_hmastlock = 1'b0; always @ (*) begin - if (bus_gnt_d) begin + if (bus_gnt_s) begin + ahblm_htrans = HTRANS_NSEQ; + ahblm_hexcl = 1'b0; + ahblm_haddr = dbg_sbus_addr; + ahblm_hsize = {1'b0, dbg_sbus_size}; + ahblm_hwrite = dbg_sbus_write; + ahblm_hprot = hprot_sbus; + end else if (bus_gnt_d) begin ahblm_htrans = HTRANS_NSEQ; ahblm_hexcl = core_aph_excl_d; ahblm_haddr = core_haddr_d; @@ -228,27 +269,32 @@ always @ (*) begin end end +assign ahblm_hwdata = bus_active_dph_s ? dbg_sbus_wdata : core_wdata_d; + // ---------------------------------------------------------------------------- // Response routing // Data buses directly connected -assign core_rdata_d = ahblm_hrdata; -assign core_rdata_i = ahblm_hrdata; -assign ahblm_hwdata = core_wdata_d; +assign core_rdata_d = ahblm_hrdata; +assign core_rdata_i = ahblm_hrdata; +assign dbg_sbus_rdata = ahblm_hrdata; // Handhshake based on grant and bus stall assign core_aph_ready_i = ahblm_hready && bus_gnt_i; -assign core_dph_ready_i = ahblm_hready && bus_active_dph_i; +assign core_dph_ready_i = bus_active_dph_i && ahblm_hready; assign core_dph_err_i = bus_active_dph_i && ahblm_hresp; // D-side errors are reported even when not ready, so that the core can make // use of the two-phase error response to cleanly squash a second load/store // chasing the faulting one down the pipeline. -assign core_aph_ready_d = ahblm_hready && bus_gnt_d; -assign core_dph_ready_d = ahblm_hready && bus_active_dph_d; -assign core_dph_err_d = bus_active_dph_d && ahblm_hresp; +assign core_aph_ready_d = ahblm_hready && bus_gnt_d; +assign core_dph_ready_d = bus_active_dph_d && ahblm_hready; +assign core_dph_err_d = bus_active_dph_d && ahblm_hresp; assign core_dph_exokay_d = bus_active_dph_d && ahblm_hexokay; +assign dbg_sbus_err = bus_active_dph_s && ahblm_hresp; +assign dbg_sbus_rdy = bus_active_dph_s && ahblm_hready; + endmodule `default_nettype wire diff --git a/test/formal/bus_compliance_1port/tb.v b/test/formal/bus_compliance_1port/tb.v index b8e31dd..a19f8df 100644 --- a/test/formal/bus_compliance_1port/tb.v +++ b/test/formal/bus_compliance_1port/tb.v @@ -41,6 +41,15 @@ localparam W_DATA = 32; (* keep *) wire dbg_instr_caught_exception; (* keep *) wire dbg_instr_caught_ebreak; +(*keep*) wire [31:0] dbg_sbus_addr; +(*keep*) wire dbg_sbus_write; +(*keep*) wire [1:0] dbg_sbus_size; +(*keep*) wire dbg_sbus_vld; +(*keep*) wire dbg_sbus_rdy; +(*keep*) wire dbg_sbus_err; +(*keep*) wire [31:0] dbg_sbus_wdata; +(*keep*) wire [31:0] dbg_sbus_rdata; + (* keep *) wire [31:0] irq; (* keep *) wire soft_irq; (* keep *) wire timer_irq; @@ -77,6 +86,15 @@ hazard3_cpu_1port dut ( .dbg_instr_caught_exception (dbg_instr_caught_exception), .dbg_instr_caught_ebreak (dbg_instr_caught_ebreak), + .dbg_sbus_addr (dbg_sbus_addr), + .dbg_sbus_write (dbg_sbus_write), + .dbg_sbus_size (dbg_sbus_size), + .dbg_sbus_vld (dbg_sbus_vld), + .dbg_sbus_rdy (dbg_sbus_rdy), + .dbg_sbus_err (dbg_sbus_err), + .dbg_sbus_wdata (dbg_sbus_wdata), + .dbg_sbus_rdata (dbg_sbus_rdata), + .irq (irq), .soft_irq (soft_irq), .timer_irq (timer_irq) @@ -129,4 +147,18 @@ ahbl_master_assertions d_assertions ( .src_hrdata (ahblm_hrdata) ); +sbus_assumptions sbus_assumptions ( + .clk (clk), + .rst_n (rst_n), + + .dbg_sbus_addr (dbg_sbus_addr), + .dbg_sbus_write (dbg_sbus_write), + .dbg_sbus_size (dbg_sbus_size), + .dbg_sbus_vld (dbg_sbus_vld), + .dbg_sbus_rdy (dbg_sbus_rdy), + .dbg_sbus_err (dbg_sbus_err), + .dbg_sbus_wdata (dbg_sbus_wdata), + .dbg_sbus_rdata (dbg_sbus_rdata) +); + endmodule