| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | module pattgen_chan | 
 |   import pattgen_ctrl_pkg::*; | 
 | ( | 
 |   input                       clk_i, | 
 |   input                       rst_ni, | 
 |   input  pattgen_chan_ctrl_t  ctrl_i, | 
 |   output logic                pda_o, | 
 |   output logic                pcl_o, | 
 |   output logic                event_done_o | 
 | ); | 
 |  | 
 |   logic        enable; | 
 |   logic        polarity_q; | 
 |   logic [31:0] prediv_q; | 
 |   logic [63:0] data_q; | 
 |   logic [5:0]  len_q; | 
 |   logic [9:0]  reps_q; | 
 |  | 
 |   logic        clk_en; | 
 |   logic        pcl_int_d; | 
 |   logic        pcl_int_q; | 
 |   logic [31:0] clk_cnt_d; | 
 |   logic [31:0] clk_cnt_q; | 
 |  | 
 |   logic        bit_cnt_en; | 
 |   logic [5:0]  bit_cnt_d; | 
 |   logic [5:0]  bit_cnt_q; | 
 |  | 
 |   logic        rep_cnt_en; | 
 |   logic [9:0]  rep_cnt_d; | 
 |   logic [9:0]  rep_cnt_q; | 
 |  | 
 |   logic        complete_en; | 
 |   logic        complete_d; | 
 |   logic        complete_q; | 
 |   logic        complete_q2; | 
 |  | 
 |   // only accept new control signals when | 
 |   // enable is deasserted | 
 |   assign enable = ctrl_i.enable; | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       polarity_q <=  1'h0; | 
 |       prediv_q   <= 32'h0; | 
 |       data_q     <= 64'h0; | 
 |       len_q      <=  6'h0; | 
 |       reps_q     <= 10'h0; | 
 |     end else begin | 
 |       polarity_q <= enable ? polarity_q : ctrl_i.polarity; | 
 |       prediv_q   <= enable ? prediv_q   : ctrl_i.prediv; | 
 |       data_q     <= enable ? data_q     : ctrl_i.data; | 
 |       len_q      <= enable ? len_q      : ctrl_i.len; | 
 |       reps_q     <= enable ? reps_q     : ctrl_i.reps; | 
 |     end | 
 |   end | 
 |  | 
 |   assign pcl_int_d = (!enable) ? 1'h0 : | 
 |                      (clk_cnt_q == prediv_q) ? ~pcl_int_q : pcl_int_q; | 
 |   assign clk_cnt_d = (!enable) ? 32'h0: | 
 |                      (clk_cnt_q == prediv_q) ? 32'h0 : (clk_cnt_q + 32'h1); | 
 |   assign pcl_o     = polarity_q ? ~pcl_int_q : pcl_int_q; | 
 |  | 
 |   // disable the clock if the previous pattern is complete | 
 |   assign clk_en    = ~complete_q; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       pcl_int_q <= 1'h0; | 
 |       clk_cnt_q <= 32'h0; | 
 |     end else begin | 
 |       pcl_int_q <= clk_en ? pcl_int_d : pcl_int_q; | 
 |       clk_cnt_q <= clk_en ? clk_cnt_d : clk_cnt_q; | 
 |     end | 
 |   end | 
 |  | 
 |   // Only update just before the falling edge of pcl_int | 
 |   // Exception: allow reset to zero whenever not enabled | 
 |   assign bit_cnt_en = (pcl_int_q & (clk_cnt_q == prediv_q) ) | (~enable); | 
 |   assign bit_cnt_d  = (!enable) ? 6'h0: | 
 |                       (bit_cnt_q == len_q) ? 6'h0 : bit_cnt_q + 6'h1; | 
 |   assign pda_o      = (!enable) ? 1'b0 : data_q[bit_cnt_q]; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       bit_cnt_q <= 6'h0; | 
 |     end else begin | 
 |       bit_cnt_q <= bit_cnt_en ? bit_cnt_d : bit_cnt_q; | 
 |     end | 
 |   end | 
 |  | 
 |   // Only update just bit_cnt_q rolls over to zero. | 
 |   // Exception: allow reset to zero whenever not enabled | 
 |   assign rep_cnt_en = (bit_cnt_en & (bit_cnt_q == len_q)) | (~enable); | 
 |   assign rep_cnt_d  = (!enable) ? 10'h0 : | 
 |                       (rep_cnt_q == reps_q) ? 10'h0 : rep_cnt_q + 10'h1; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       rep_cnt_q <= 10'h0; | 
 |     end else begin | 
 |       rep_cnt_q <= rep_cnt_en ? rep_cnt_d : rep_cnt_q; | 
 |     end | 
 |   end | 
 |  | 
 |   // flip the complete bit to 1 whenever the rep_cnt is about to roll over to zero. | 
 |   // Also clear to zero whenever not enabled. | 
 |   assign complete_en = (rep_cnt_en & (rep_cnt_q == reps_q)) | (~enable); | 
 |   assign complete_d  = (!enable) ? 1'h0 : 1'h1; | 
 |  | 
 |   always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |     if (!rst_ni) begin | 
 |       complete_q  <= 1'h0; | 
 |       complete_q2 <= 1'h0; | 
 |     end else begin | 
 |       complete_q  <= complete_en ? complete_d : complete_q; | 
 |       complete_q2 <= complete_q; | 
 |     end | 
 |   end | 
 |  | 
 |   assign event_done_o = complete_q & ~complete_q2; | 
 |  | 
 | endmodule : pattgen_chan |