|  | // 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 |