From 0e7117fbec434fcfdf2bcce4ed379d34cdbe68b4 Mon Sep 17 00:00:00 2001 From: Michael Schaffner Date: Thu, 15 Apr 2021 18:23:38 -0700 Subject: [PATCH] [lockstep] Introduce optimization barrier around lockstep Ibex Certain synthesis tools like DC are very smart at optimizing away redundant logic. Hence, we have to insert an optimization barrier at the IOs of the lockstep Ibex. This is achieved by manually buffering each bit using prim_buf. Our Xilinx and DC synthesis flows make sure that these buffers cannot be optimized away using keep attributes (Vivado) and size_only constraints (DC). Signed-off-by: Michael Schaffner --- ibex_top.core | 1 + rtl/ibex_top.sv | 323 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 278 insertions(+), 46 deletions(-) diff --git a/ibex_top.core b/ibex_top.core index ef27228b..823382a6 100644 --- a/ibex_top.core +++ b/ibex_top.core @@ -10,6 +10,7 @@ filesets: depend: - lowrisc:ibex:ibex_pkg - lowrisc:ibex:ibex_core + - lowrisc:prim:buf files: - rtl/ibex_register_file_ff.sv # generic FF-based - rtl/ibex_register_file_fpga.sv # FPGA diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index fd0d96c9..07e248dd 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -416,6 +416,225 @@ module ibex_top #( // Redundant lockstep core implementation if (Lockstep) begin : gen_lockstep + // Note: certain synthesis tools like DC are very smart at optimizing away redundant logic. + // Hence, we have to insert an optimization barrier at the IOs of the lockstep Ibex. + // This is achieved by manually buffering each bit using prim_buf. + // Our Xilinx and DC synthesis flows make sure that these buffers cannot be optimized away + // using keep attributes (Vivado) and size_only constraints (DC). + + localparam int NumBufferBits = $bits({ + hart_id_i, + boot_addr_i, + instr_req_o, + instr_gnt_i, + instr_rvalid_i, + instr_addr_o, + instr_rdata_i, + instr_err_i, + data_req_o, + data_gnt_i, + data_rvalid_i, + data_we_o, + data_be_o, + data_addr_o, + data_wdata_o, + data_rdata_i, + data_err_i, + dummy_instr_id, + rf_raddr_a, + rf_raddr_b, + rf_waddr_wb, + rf_we_wb, + rf_wdata_wb_ecc, + rf_rdata_a_ecc, + rf_rdata_b_ecc, + ic_tag_req, + ic_tag_write, + ic_tag_addr, + ic_tag_wdata, + ic_data_req, + ic_data_write, + ic_data_addr, + ic_data_wdata, + irq_software_i, + irq_timer_i, + irq_external_i, + irq_fast_i, + irq_nm_i, + irq_pending, + debug_req_i, + crash_dump_o, + core_busy_d + }); + + logic [NumBufferBits-1:0] buf_in, buf_out; + + logic [31:0] hart_id_local; + logic [31:0] boot_addr_local; + + logic instr_req_local; + logic instr_gnt_local; + logic instr_rvalid_local; + logic [31:0] instr_addr_local; + logic [31:0] instr_rdata_local; + logic instr_err_local; + + logic data_req_local; + logic data_gnt_local; + logic data_rvalid_local; + logic data_we_local; + logic [3:0] data_be_local; + logic [31:0] data_addr_local; + logic [31:0] data_wdata_local; + logic [31:0] data_rdata_local; + logic data_err_local; + + logic dummy_instr_id_local; + logic [4:0] rf_raddr_a_local; + logic [4:0] rf_raddr_b_local; + logic [4:0] rf_waddr_wb_local; + logic rf_we_wb_local; + logic [RegFileDataWidth-1:0] rf_wdata_wb_ecc_local; + logic [RegFileDataWidth-1:0] rf_rdata_a_ecc_local; + logic [RegFileDataWidth-1:0] rf_rdata_b_ecc_local; + + logic [IC_NUM_WAYS-1:0] ic_tag_req_local; + logic ic_tag_write_local; + logic [IC_INDEX_W-1:0] ic_tag_addr_local; + logic [TagSizeECC-1:0] ic_tag_wdata_local; + logic [IC_NUM_WAYS-1:0] ic_data_req_local; + logic ic_data_write_local; + logic [IC_INDEX_W-1:0] ic_data_addr_local; + logic [LineSizeECC-1:0] ic_data_wdata_local; + + logic irq_software_local; + logic irq_timer_local; + logic irq_external_local; + logic [14:0] irq_fast_local; + logic irq_nm_local; + logic irq_pending_local; + + logic debug_req_local; + crash_dump_t crash_dump_local; + + logic core_busy_local; + + assign buf_in = { + hart_id_i, + boot_addr_i, + instr_req_o, + instr_gnt_i, + instr_rvalid_i, + instr_addr_o, + instr_rdata_i, + instr_err_i, + data_req_o, + data_gnt_i, + data_rvalid_i, + data_we_o, + data_be_o, + data_addr_o, + data_wdata_o, + data_rdata_i, + data_err_i, + dummy_instr_id, + rf_raddr_a, + rf_raddr_b, + rf_waddr_wb, + rf_we_wb, + rf_wdata_wb_ecc, + rf_rdata_a_ecc, + rf_rdata_b_ecc, + ic_tag_req, + ic_tag_write, + ic_tag_addr, + ic_tag_wdata, + ic_data_req, + ic_data_write, + ic_data_addr, + ic_data_wdata, + irq_software_i, + irq_timer_i, + irq_external_i, + irq_fast_i, + irq_nm_i, + irq_pending, + debug_req_i, + crash_dump_o, + core_busy_d + }; + + assign { + hart_id_local, + boot_addr_local, + instr_req_local, + instr_gnt_local, + instr_rvalid_local, + instr_addr_local, + instr_rdata_local, + instr_err_local, + data_req_local, + data_gnt_local, + data_rvalid_local, + data_we_local, + data_be_local, + data_addr_local, + data_wdata_local, + data_rdata_local, + data_err_local, + dummy_instr_id_local, + rf_raddr_a_local, + rf_raddr_b_local, + rf_waddr_wb_local, + rf_we_wb_local, + rf_wdata_wb_ecc_local, + rf_rdata_a_ecc_local, + rf_rdata_b_ecc_local, + ic_tag_req_local, + ic_tag_write_local, + ic_tag_addr_local, + ic_tag_wdata_local, + ic_data_req_local, + ic_data_write_local, + ic_data_addr_local, + ic_data_wdata_local, + irq_software_local, + irq_timer_local, + irq_external_local, + irq_fast_local, + irq_nm_local, + irq_pending_local, + debug_req_local, + crash_dump_local, + core_busy_local + } = buf_out; + + // Manually buffer all input signals. + for (genvar k = 0; k < NumBufferBits; k++) begin : gen_buffers + prim_buf u_prim_buf ( + .in_i(buf_in[k]), + .out_o(buf_out[k]) + ); + end + + logic [TagSizeECC-1:0] ic_tag_rdata_local [IC_NUM_WAYS]; + logic [LineSizeECC-1:0] ic_data_rdata_local [IC_NUM_WAYS]; + for (genvar k = 0; k < IC_NUM_WAYS; k++) begin : gen_ways + for (genvar j = 0; j < TagSizeECC; j++) begin : gen_tag_bufs + prim_buf u_prim_buf ( + .in_i(ic_tag_rdata[k][j]), + .out_o(ic_tag_rdata_local[k][j]) + ); + end + for (genvar j = 0; j < TagSizeECC; j++) begin : gen_data_bufs + prim_buf u_prim_buf ( + .in_i(ic_data_rdata[k][j]), + .out_o(ic_data_rdata_local[k][j]) + ); + end + end + + logic lockstep_alert_minor_local, lockstep_alert_major_local; ibex_lockstep #( .PMPEnable ( PMPEnable ), .PMPGranularity ( PMPGranularity ), @@ -445,60 +664,72 @@ module ibex_top #( .clk_i (clk), .rst_ni (rst_ni), - .hart_id_i (hart_id_i), - .boot_addr_i (boot_addr_i), + .hart_id_i (hart_id_local), + .boot_addr_i (boot_addr_local), - .instr_req_i (instr_req_o), - .instr_gnt_i (instr_gnt_i), - .instr_rvalid_i (instr_rvalid_i), - .instr_addr_i (instr_addr_o), - .instr_rdata_i (instr_rdata_i), - .instr_err_i (instr_err_i), + .instr_req_i (instr_req_local), + .instr_gnt_i (instr_gnt_local), + .instr_rvalid_i (instr_rvalid_local), + .instr_addr_i (instr_addr_local), + .instr_rdata_i (instr_rdata_local), + .instr_err_i (instr_err_local), - .data_req_i (data_req_o), - .data_gnt_i (data_gnt_i), - .data_rvalid_i (data_rvalid_i), - .data_we_i (data_we_o), - .data_be_i (data_be_o), - .data_addr_i (data_addr_o), - .data_wdata_i (data_wdata_o), - .data_rdata_i (data_rdata_i), - .data_err_i (data_err_i), + .data_req_i (data_req_local), + .data_gnt_i (data_gnt_local), + .data_rvalid_i (data_rvalid_local), + .data_we_i (data_we_local), + .data_be_i (data_be_local), + .data_addr_i (data_addr_local), + .data_wdata_i (data_wdata_local), + .data_rdata_i (data_rdata_local), + .data_err_i (data_err_local), - .dummy_instr_id_i (dummy_instr_id), - .rf_raddr_a_i (rf_raddr_a), - .rf_raddr_b_i (rf_raddr_b), - .rf_waddr_wb_i (rf_waddr_wb), - .rf_we_wb_i (rf_we_wb), - .rf_wdata_wb_ecc_i (rf_wdata_wb_ecc), - .rf_rdata_a_ecc_i (rf_rdata_a_ecc), - .rf_rdata_b_ecc_i (rf_rdata_b_ecc), + .dummy_instr_id_i (dummy_instr_id_local), + .rf_raddr_a_i (rf_raddr_a_local), + .rf_raddr_b_i (rf_raddr_b_local), + .rf_waddr_wb_i (rf_waddr_wb_local), + .rf_we_wb_i (rf_we_wb_local), + .rf_wdata_wb_ecc_i (rf_wdata_wb_ecc_local), + .rf_rdata_a_ecc_i (rf_rdata_a_ecc_local), + .rf_rdata_b_ecc_i (rf_rdata_b_ecc_local), - .ic_tag_req_i (ic_tag_req), - .ic_tag_write_i (ic_tag_write), - .ic_tag_addr_i (ic_tag_addr), - .ic_tag_wdata_i (ic_tag_wdata), - .ic_tag_rdata_i (ic_tag_rdata), - .ic_data_req_i (ic_data_req), - .ic_data_write_i (ic_data_write), - .ic_data_addr_i (ic_data_addr), - .ic_data_wdata_i (ic_data_wdata), - .ic_data_rdata_i (ic_data_rdata), + .ic_tag_req_i (ic_tag_req_local), + .ic_tag_write_i (ic_tag_write_local), + .ic_tag_addr_i (ic_tag_addr_local), + .ic_tag_wdata_i (ic_tag_wdata_local), + .ic_tag_rdata_i (ic_tag_rdata_local), + .ic_data_req_i (ic_data_req_local), + .ic_data_write_i (ic_data_write_local), + .ic_data_addr_i (ic_data_addr_local), + .ic_data_wdata_i (ic_data_wdata_local), + .ic_data_rdata_i (ic_data_rdata_local), - .irq_software_i (irq_software_i), - .irq_timer_i (irq_timer_i), - .irq_external_i (irq_external_i), - .irq_fast_i (irq_fast_i), - .irq_nm_i (irq_nm_i), - .irq_pending_i (irq_pending), + .irq_software_i (irq_software_local), + .irq_timer_i (irq_timer_local), + .irq_external_i (irq_external_local), + .irq_fast_i (irq_fast_local), + .irq_nm_i (irq_nm_local), + .irq_pending_i (irq_pending_local), - .debug_req_i (debug_req_i), - .crash_dump_i (crash_dump_o), + .debug_req_i (debug_req_local), + .crash_dump_i (crash_dump_local), - .alert_minor_o (lockstep_alert_minor), - .alert_major_o (lockstep_alert_major), - .core_busy_i (core_busy_d) + .alert_minor_o (lockstep_alert_minor_local), + .alert_major_o (lockstep_alert_major_local), + .core_busy_i (core_busy_local) ); + + // Manually buffer the output signals. + prim_buf u_prim_buf_alert_minor ( + .in_i(lockstep_alert_minor_local), + .out_o(lockstep_alert_minor) + ); + + prim_buf u_prim_buf_alert_major ( + .in_i(lockstep_alert_major_local), + .out_o(lockstep_alert_major) + ); + end else begin : gen_no_lockstep assign lockstep_alert_major = 1'b0; assign lockstep_alert_minor = 1'b0;