//============================================================================ // University of Virginia //============================================================================ // Contact: sgoadhouse@virginia.edu, phys-electronics@virginia.edu //============================================================================ // CrossClock - A generic module to handle transferring data across clock // domain boundaries. The 'sendBtoA_i' signal is to be set high // when data is to be transferred. 'DataBtoA_i' is then sent across // the boundary to 'DataBtoA_o' with 'sentBtoA_o' indicating when // safe to access 'DataBtoA_o'. Then 'DataAtoB_i' is transferred to // 'DataAtoB_o' with 'recvAtoB_o' indicating when safe to access // 'DataAtoB_o'. 'sendBtoA_i' can be kept high for multiple // transfers. Use 'recvAtoB_o' to indicate when to modify // 'DataBtoA_i' in a single clkB cycle. The parameter 'WAIT_STATES_A' // is a delay in clkA cycles to wait between 'sentBtoA_o' and // when 'DataAtoB_i' is latched internally. //============================================================================ module CrossClock_RX // Change these when instantiating. #(parameter DataBtoA_SZ = 65, // Number of bits in DataBtoA (write data) parameter DataAtoB_SZ = 32, // Number of bits in DataAtoB (read data) parameter WAIT_STATES_A = 8) // WAIT_STATES_A can NOT be less than 3 (input resetA, input clkA, input clkA_en, output sentBtoA_o, output reg strbAtoB_o, // mainly used for debugging input [DataAtoB_SZ-1:0] DataAtoB_i, output [DataBtoA_SZ-1:0] DataBtoA_o, input clkB, input sendBtoA_i, output recvAtoB_o, input [DataBtoA_SZ-1:0] DataBtoA_i, output [DataAtoB_SZ-1:0] DataAtoB_o); // Make the shiftA shift register WAIT_STATES_A+1 f/fs. This // includes a sync f/f at shiftA[0] and an ack back to domain B at // shiftA[SHIFTA_MSB]. Must have at least 4 f/fs for operation. parameter SHIFTA_MSB = ((WAIT_STATES_A < 3) ? 3 : WAIT_STATES_A); reg [SHIFTA_MSB:0] shiftA; reg [2:0] shiftB; reg [DataAtoB_SZ-1:0] DataAtoB_reg; // There are two clock domains in this module, A & B, so great care // must be taken to avoid bit errors due to possible meta-stability // that can occur if a flip/flop input bit changes within the setup // or hold time window of the flip/flop. So a strobe signal, // sendBtoA_i, will be used to cross the clock domains and exit as // sentBtoA_o in order to flag when it is safe to use DataBtoA_o // bits. The strobe signal will first go from clkB to clkA. Once it // is stable there, it will exit the module to external logic, as // sentBtoA_o, and also start a WAIT timer that runs at clkA. Once // the WAIT timer expires, an ack signal will be generated in the // clkA domain. This ack will be used to strobe in read data in the // clkA domain. This ack signal will then cross into the clkB // clock domain. Once it is safely within the clkB domain, it will // be sent to the clkB logic as recvAtoB_o. This provides // sufficient time for the strobed data bits from A to settle // before being accessed by the clkB logic. // Cross clock domain. always @(posedge clkA) if(clkA_en) begin // Sync sendBtoA_i to clkA. If sendBtoA_i is staying high for // multiple transactions, when the strobe signal passes // through the clkA domain and back to the clkB domain, // eventually shiftB[2] will go high causing shiftA[0] to be // clocked low. This 0 in shiftA[0] will bypass the WAIT // timer shift register and make the output of shiftA go low // on the next clock. This 0 goes back to the B domain // causing shiftB[2] to go low. At this point, shiftA[0] // goes back high, as long as sendBtoA_i is high, and the // next transaction will take place, while carefully assuring // that the strobe signal is safely crossing clock domains. // // Use a shift register in the clkA domain to handle both // syncing to the clkA domain and wait states. if (resetA | (shiftA[2] & ~shiftA[1])) begin // resetA == 1 or falling edge of shiftA input will reset entire shiftA shiftA <= 0; end else begin // shiftA <= {shiftA[SHIFTA_MSB-1:0], (sendBtoA_i & ~shiftB[2])}; shiftA <= {shiftA[SHIFTA_MSB-1:0], shiftB[2]}; end // At end of wait states, use the rising edge of // shiftA[SHIFTA_MSB-1] to strobe in read data (DataAtoB_i). // However, since registering strbAtoB_o, need to use the // rising edge of shiftA[SHIFTA_MSB-2] to get the timing correct. // // A sync'ed version of shiftA[SHIFTA_MSB] will be used in B to // indicate that DataAtoB_i has been strobed. strbAtoB_o <= shiftA[SHIFTA_MSB-2] & ~shiftA[SHIFTA_MSB-1]; // Strobe in DataAtoB_i data on rising edge of the last bit in shiftA, which // indicates that the WAIT period is complete. if (strbAtoB_o) begin DataAtoB_reg <= DataAtoB_i; end end // always @ (posedge clkA) // sentBtoA_o comes from shiftA[1]. This is the first element of // shiftA safe to be used without the chance of metastability. assign sentBtoA_o = shiftA[1]; // NOTE: Assuming that by holding off on recvAtoB_o via cross clock // domain f/fs, DataBtoA_i will be stable until after they are clocked // by clkA outside of this module. // // Not using f/fs for DataBtoA_o to prevent the case of a bit f/f // going metastable and creating a bit error. assign DataBtoA_o = DataBtoA_i; // Cross clock domain. always @(posedge clkB) begin // cross back to clkB domain with the ack, shiftA[SHIFTA_MSB]. // When shiftB[1] goes high, we know that there has seen at // least one stable clkA rising edge. // shiftB <= {shiftB[1:0], shiftA[SHIFTA_MSB]}; shiftB <= {(sendBtoA_i & ~shiftB[1]),shiftB[0], shiftA[SHIFTA_MSB]}; end // DataAtoB_reg is strobed by clkA but held until // shiftA[SHIFTA_MSB] propogates to shiftB[1]. assign DataAtoB_o = DataAtoB_reg; assign recvAtoB_o = shiftB[1]; endmodule