diff --git a/lib/verilog/tuner/tuner_ctrl_txn_adapter.sv b/lib/verilog/tuner/tuner_ctrl_txn_adapter.sv new file mode 100644 index 0000000..5d7b37b --- /dev/null +++ b/lib/verilog/tuner/tuner_ctrl_txn_adapter.sv @@ -0,0 +1,66 @@ +//============================================================================== +// Adapter between tuner_txn_if and existing tuner_ctrl_arb_if +// Moves the micro handshaking logic into one place so controllers only +// issue a single transaction. +//============================================================================== + +`timescale 1ns/1ps +`default_nettype none + +module tuner_ctrl_txn_adapter #( + parameter int DAC_WIDTH = 8, + parameter int ADC_WIDTH = 8, + parameter tuner_phy_pkg::tuner_ctrl_ch_e CHANNEL = tuner_phy_pkg::CH_SEARCH +) ( + input logic i_clk, + input logic i_rst, + tuner_txn_if.arb txn_if, + tuner_ctrl_arb_if.producer ctrl_if +); + import tuner_phy_pkg::*; + + typedef enum logic [1:0] {IDLE, WAIT_TUNE, WAIT_COMMIT, RESP} state_e; + state_e state, state_next; + logic refresh_pulse; + + // State machine + always_ff @(posedge i_clk or posedge i_rst) begin + if (i_rst) begin + state <= IDLE; + end else begin + state <= state_next; + end + end + + always_comb begin + state_next = state; + unique case (state) + IDLE: if (txn_if.val) state_next = WAIT_TUNE; + WAIT_TUNE: if (ctrl_if.get_ctrl_tune_ack(CHANNEL)) state_next = WAIT_COMMIT; + WAIT_COMMIT: if (ctrl_if.get_ctrl_commit_ack(CHANNEL)) state_next = RESP; + RESP: if (txn_if.fire()) state_next = IDLE; + endcase + end + + // Refresh pulse when new transaction begins + always_ff @(posedge i_clk or posedge i_rst) begin + if (i_rst) refresh_pulse <= 1'b0; + else refresh_pulse <= (state == IDLE) && (state_next == WAIT_TUNE); + end + + // Drive control arbiter interface + assign ctrl_if.ctrl_active[CHANNEL] = (state != IDLE); + assign ctrl_if.ctrl_refresh[CHANNEL] = refresh_pulse; + + assign ctrl_if.ring_tune[CHANNEL] = txn_if.tune_code; + assign ctrl_if.tune_val[CHANNEL] = (state == WAIT_TUNE) && txn_if.val; + + assign ctrl_if.commit_rdy[CHANNEL] = (state == WAIT_COMMIT); + + // Pass measurement back on RESP state + assign txn_if.rdy = (state == RESP); + assign txn_if.meas_power = ctrl_if.pwr_commit; + +endmodule + +`default_nettype wire diff --git a/lib/verilog/tuner/tuner_phy.sv b/lib/verilog/tuner/tuner_phy.sv index 4d7b1a8..27b0599 100644 --- a/lib/verilog/tuner/tuner_phy.sv +++ b/lib/verilog/tuner/tuner_phy.sv @@ -74,6 +74,14 @@ module tuner_phy #( .i_clk(i_clk), .i_rst(i_rst) ); + + tuner_txn_if #( + .DAC_WIDTH(DAC_WIDTH), + .ADC_WIDTH(ADC_WIDTH) + ) search_txn_if ( + .i_clk(i_clk), + .i_rst(i_rst) + ); // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- @@ -102,6 +110,17 @@ module tuner_phy #( .o_afe_ring_tune_val() ); + tuner_ctrl_txn_adapter #( + .DAC_WIDTH(DAC_WIDTH), + .ADC_WIDTH(ADC_WIDTH), + .CHANNEL(CH_SEARCH) + ) search_txn_adapter ( + .i_clk(i_clk), + .i_rst(i_rst), + .txn_if(search_txn_if.arb), + .ctrl_if(ctrl_arb_if.producer) + ); + tuner_search_phy #( .DAC_WIDTH(DAC_WIDTH), .ADC_WIDTH(ADC_WIDTH), @@ -116,7 +135,7 @@ module tuner_phy #( .i_dig_ring_tune_end(i_cfg_ring_tune_end), .i_dig_ring_tune_stride(i_cfg_ring_tune_stride), - .ctrl_arb_if(ctrl_arb_if.producer), + .txn_if(search_txn_if.ctrl), .search_if(search_if), .o_dig_ring_tune(search_phy_ring_tune) ); diff --git a/lib/verilog/tuner/tuner_search_phy.sv b/lib/verilog/tuner/tuner_search_phy.sv index d95961b..a52c8d8 100644 --- a/lib/verilog/tuner/tuner_search_phy.sv +++ b/lib/verilog/tuner/tuner_search_phy.sv @@ -42,8 +42,8 @@ module tuner_search_phy #( /*// Power Detector Interface *tuner_pwr_detect_if.consumer pwr_detect_if,*/ - // Controller Arbiter Interface - tuner_ctrl_arb_if.producer ctrl_arb_if, + // Tuning transaction interface + tuner_txn_if.ctrl txn_if, // Search Interface for local search tuner_search_if.producer search_if, @@ -81,9 +81,6 @@ module tuner_search_phy #( /*typedef tuner_pwr_detect_if.pwr_detect_state_e search_active_state_e;*/ /*typedef tuner_phy_detect_if_state_e search_active_state_e;*/ - // Arbiter I/F state for communication with ring tuner and power detector - // This is currently the only substate in SEARCH_ACTIVE - typedef tuner_phy_ctrl_arb_if_state_e search_active_state_e; // First half [0:SEARCH_PEAK_WINDOW_HALFSIZE-1] // Second half [SEARCH_PEAK_WINDOW_HALFSIZE:2*SEARCH_PEAK_WINDOW_HALFSIZE-1] @@ -110,29 +107,17 @@ module tuner_search_phy #( /*logic pwr_read_fire;*/ /*logic pwr_detect_fire;*/ - logic is_ctrl_active_state; - logic is_tune_state; - logic is_update_state; - logic tune_fire; - logic commit_fire; - logic tune_compute; - logic tune_compute_done; - logic update_commit_done; - - // Refactored into pwr_detect_if - // Internal state within SEARCH_ACTIVE - // Reintroduced for controller arbiter i/f - search_active_state_e search_active_state, search_active_state_next; + logic txn_valid; int search_active_cnt; int search_active_cnt_max; logic search_active_update; logic search_active_done; + logic is_ctrl_active_state; logic [DAC_WIDTH-1:0] ring_tune_step; logic [DAC_WIDTH-1:0] ring_tune; /*logic [DAC_WIDTH-1:0] ring_tune_prev;*/ - logic [DAC_WIDTH-1:0] ring_tune_next; /*logic [ADC_WIDTH-1:0] ring_pwr_detected; *logic [ADC_WIDTH-1:0] ring_pwr_detected_prev;*/ @@ -255,103 +240,32 @@ module tuner_search_phy #( *assign pwr_detect_if.pwr_detect_refresh = (state == SEARCH_INIT); *assign search_active_update = pwr_detect_if.pwr_detect_update;*/ // ---------------------------------------------------------------------- - - // ---------------------------------------------------------------------- - // SEARCH_ACTIVE - Controller Arbiter I/F + // SEARCH_ACTIVE - Transaction I/F // ---------------------------------------------------------------------- - // Super-state for active control assign is_ctrl_active_state = (state == SEARCH_ACTIVE); - // Update sub-state: receive committed ring tune and power - assign is_update_state = is_ctrl_active_state && (search_active_state == CTRL_UPDATE); - // Tune sub-state: compute tuner code - assign is_tune_state = is_ctrl_active_state && (search_active_state == CTRL_TUNE); - - assign tune_fire = ctrl_arb_if.get_ctrl_tune_ack(CH_SEARCH); - assign commit_fire = ctrl_arb_if.get_ctrl_commit_ack(CH_SEARCH); - - // Internal state for controller arbiter - always_ff @(posedge i_clk or posedge i_rst) begin - if (i_rst) begin - search_active_state <= CTRL_TUNE; // Start with CTRL_TUNE - end - else if (search_refresh) begin - search_active_state <= CTRL_TUNE; // Reset to CTRL_TUNE on refresh - end - else begin - search_active_state <= search_active_state_next; - end - end - - // Advance states only at SEARCH_ACTIVE - always_comb begin - search_active_state_next = search_active_state; - if (is_ctrl_active_state) begin - case (search_active_state) - CTRL_TUNE: if (tune_fire) search_active_state_next = CTRL_UPDATE; - CTRL_UPDATE: if (commit_fire) search_active_state_next = CTRL_TUNE; - default: search_active_state_next = CTRL_UPDATE; // Reset to CTRL_TUNE on error - endcase - end - end - - /*assign ctrl_arb_if.ctrl_active = is_ctrl_active_state; - *assign ctrl_arb_if.ctrl_refresh = search_refresh;*/ - assign ctrl_arb_if.ctrl_active[CH_SEARCH] = is_ctrl_active_state; - assign ctrl_arb_if.ctrl_refresh[CH_SEARCH] = search_refresh; - - assign ctrl_arb_if.tune_val[CH_SEARCH] = is_tune_state && tune_compute_done; + assign search_active_update = txn_if.fire(); + assign txn_if.val = is_ctrl_active_state && txn_valid; + assign txn_if.tune_code = ring_tune; - // commit is instantaneous - assign update_commit_done = is_update_state; - assign ctrl_arb_if.commit_rdy[CH_SEARCH] = is_update_state && update_commit_done; - - /*assign search_active_update = is_ctrl_active_state && ctrl_arb_if.get_ctrl_commit_ack(CH_SEARCH);*/ - assign search_active_update = is_ctrl_active_state && commit_fire; - // compute start at the next cycle after commit - /*assign tune_compute_start = search_active_update;*/ // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // SEARCH_ACTIVE - Ring Tuning // ---------------------------------------------------------------------- - // Step ring tuner at pwr detect (let pwr detector to deal with analog delays) assign ring_tune_step = (1 << i_dig_ring_tune_stride); - assign tune_compute = is_tune_state && !tune_compute_done; always_ff @(posedge i_clk or posedge i_rst) begin if (i_rst) begin ring_tune <= '0; - end - else if (search_refresh) begin + end else if (search_refresh) begin ring_tune <= i_dig_ring_tune_start; - end - else if (tune_compute) begin + end else if (txn_if.fire()) begin ring_tune <= ring_tune + ring_tune_step; end end - always_ff @(posedge i_clk or posedge i_rst) begin - if (i_rst) begin - tune_compute_done <= 1'b0; - end - else if (search_refresh) begin - tune_compute_done <= 1'b0; - end - // Assume single-cycle tuner code compute (toggle done immediately) - else if (is_tune_state) begin - tune_compute_done <= 1'b1; - end - else if (is_update_state) begin - tune_compute_done <= 1'b0; - end - end - - /*assign o_dig_ring_tune = ring_tune;*/ - assign ctrl_arb_if.ring_tune[CH_SEARCH] = ring_tune; - // ---------------------------------------------------------------------- + assign o_dig_ring_tune = ring_tune; - // ---------------------------------------------------------------------- - // SEARCH_ACTIVE - Count // ---------------------------------------------------------------------- // Count the number of power detections taken during SEARCH_ACTIVE assign search_active_cnt_max = (i_dig_ring_tune_end - i_dig_ring_tune_start) >> i_dig_ring_tune_stride; @@ -368,6 +282,18 @@ module tuner_search_phy #( search_active_cnt <= search_active_cnt + 1; end end + + always_ff @(posedge i_clk or posedge i_rst) begin + if (i_rst) begin + txn_valid <= 1'b0; + end + else if (search_refresh) begin + txn_valid <= 1'b1; + end + else if (txn_if.fire()) begin + txn_valid <= ~search_active_done; + end + end // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- @@ -387,13 +313,8 @@ module tuner_search_phy #( end else if (search_active_update) begin // Receive the committed ring tune and power from the controller arbiter - pwr_det_track <= ctrl_arb_if.pwr_commit; - ring_tune_track <= ctrl_arb_if.ring_tune_commit; - end - end - - // Majority-Vote - /*assign pwr_incremented = (i_dig_pwr_detected > pwr_detected_track_window[0]);*/ + pwr_det_track <= txn_if.meas_power; + ring_tune_track <= ring_tune; /*assign pwr_decremented = (i_dig_pwr_detected < pwr_detected_track_window[0]);*/ assign pwr_incremented = pwr_det_track_win[0] > pwr_det_track_win[1]; assign pwr_decremented = pwr_det_track_win[0] < pwr_det_track_win[1]; diff --git a/lib/verilog/tuner/tuner_txn_if.sv b/lib/verilog/tuner/tuner_txn_if.sv new file mode 100644 index 0000000..c9a5928 --- /dev/null +++ b/lib/verilog/tuner/tuner_txn_if.sv @@ -0,0 +1,44 @@ +//============================================================================== +// Tuner transaction interface +// Provides a combined request/response handshake for tuning operations. +//============================================================================== + +`timescale 1ns/1ps +`default_nettype none + +interface tuner_txn_if #( + parameter int DAC_WIDTH = 8, + parameter int ADC_WIDTH = 8 +) ( + input logic i_clk, + input logic i_rst +); + logic val; + logic rdy; + logic [DAC_WIDTH-1:0] tune_code; + logic [ADC_WIDTH-1:0] meas_power; + + function automatic logic fire(); + return val & rdy; + endfunction + + // Controller side + modport ctrl( + output val, + output tune_code, + input rdy, + input meas_power, + import fire + ); + + // Arbiter side + modport arb( + input val, + input tune_code, + output rdy, + output meas_power, + import fire + ); +endinterface + +`default_nettype wire