@@ -31,7 +31,7 @@ module hyperbus_rwds_sampler import hyperbus_pkg::*; #()
31
31
input logic rst_ni,
32
32
input logic test_mode_i,
33
33
34
- input logic [1 : 0 ] cfg_edge_idx_i, // #edge where rwds is sampled
34
+ input logic [3 : 0 ] cfg_edge_idx_i, // #edge where rwds is sampled
35
35
input logic cfg_edge_pol_i, // 1: rising, 0: falling
36
36
37
37
// sampled value going to PHY-FSM
@@ -42,65 +42,54 @@ module hyperbus_rwds_sampler import hyperbus_pkg::*; #()
42
42
43
43
// physical HyperBus signals
44
44
input logic hyper_cs_ni,
45
- input logic hyper_ck_i,
46
- input logic hyper_ck_ni,
47
45
input logic hyper_rwds_i
48
46
);
49
47
50
48
// used to time the sampling of RWDS to determine additional latency
51
- logic [2 : 0 ] cnt_edge_d, cnt_edge_q; // one bit larger than config
52
- logic start_of_tf_d, start_of_tf_q; // start of transfer indicator
53
- logic [2 : 0 ] cnt_target_value;
54
- logic cnt_at_target;
49
+ logic tx_clk_270; // inverted 90deg clock
50
+ logic [4 : 0 ] cnt_edge_d, cnt_edge_q; // one bit larger than config
55
51
logic cnt_clk; // clock used for edge counting
56
52
logic sampling_clk, sampling_clk_gated; // clock used for sampling
57
53
logic enable_sampling; // sampling clock gate enable
58
54
logic rwds_sample;
59
55
60
- assign cnt_target_value = cfg_edge_idx_i + 1 ;
61
- assign cnt_at_target = (cnt_target_value == cnt_edge_q);
62
-
56
+ // generate and select clocks
57
+ // Sampling is either clocked by un-inverted or inverted 90deg hyperbus clock
58
+ // Counter is clocked by the inverse as it controls the clock gate
59
+ // which should be on for one cycle with sampling edge in the middle
60
+ tc_clk_inverter i_tx_clk_inv (
61
+ .clk_i ( tx_clk_90_i ),
62
+ .clk_o ( tx_clk_270 )
63
+ );
64
+
65
+ tc_clk_mux2 i_sampling_clk_mux (
66
+ .clk0_i ( tx_clk_270 ),
67
+ .clk1_i ( tx_clk_90_i ),
68
+ .clk_sel_i ( cfg_edge_pol_i ),
69
+ .clk_o ( sampling_clk )
70
+ );
71
+
72
+ tc_clk_inverter i_edge_cnt_clk_inv (
73
+ .clk_i ( sampling_clk ),
74
+ .clk_o ( cnt_clk )
75
+ );
76
+
63
77
always_comb begin : gen_edge_cnt
64
- // only count at the start of a transfer
65
- if (start_of_tf_q) begin
66
- cnt_edge_d = cnt_edge_q + 1 ; // count hyper_ck(_n) edges
78
+ // only count during transfers
79
+ if (~ hyper_cs_ni) begin
80
+ cnt_edge_d = cnt_edge_q + 1 ;
81
+ if (cnt_edge_q == '1 ) begin
82
+ cnt_edge_d = cnt_edge_q; // saturating counter
83
+ end
67
84
end else begin
68
- // reset counter for next start of transfer
85
+ // reset counter for next transfer
69
86
cnt_edge_d = 1'b0 ;
70
87
end
71
88
end
72
- // sampling on the rising edge requires counting on falling edges to create
73
- // a window where the clk-gate is transparent around rising edge and vice versa
74
- tc_clk_mux2 i_cnt_clk_mux (
75
- .clk0_i ( hyper_ck_ni ),
76
- .clk1_i ( hyper_ck_i ),
77
- .clk_sel_i ( ~ cfg_edge_pol_i ),
78
- .clk_o ( cnt_clk )
79
- );
80
89
81
90
`FF (cnt_edge_q, cnt_edge_d, '0 , cnt_clk);
82
91
83
- // used to reset counter and ensure clock gate opens only once
84
- // clocked with ungated clock to detect cs_n going high
85
- always_comb begin : gen_start_of_transfer
86
- start_of_tf_d = start_of_tf_q;
87
- if (hyper_cs_ni) begin
88
- start_of_tf_d = 1'b1 ;
89
- end else if (cnt_at_target) begin
90
- start_of_tf_d = 1'b0 ;
91
- end
92
- end
93
- `FF (start_of_tf_q, start_of_tf_d, '0 , tx_clk_90_i);
94
-
95
- // TODO: Check proper sampling point in sim
96
- assign enable_sampling = (cnt_at_target && start_of_tf_q);
97
-
98
- tc_clk_mux2 i_sampling_clk_mux (
99
- .clk0_i ( hyper_ck_ni ),
100
- .clk1_i ( hyper_ck_i ),
101
- .clk_sel_i ( cfg_edge_pol_i ),
102
- .clk_o ( sampling_clk )
103
- );
92
+ assign enable_sampling = (cnt_edge_q == cfg_edge_idx_i);
104
93
105
94
// gate the sampling of rwds to the selected clock edge
106
95
tc_clk_gating i_rwds_sample_rise_gate (
0 commit comments