blob: 4f4c67dc2ae6507a38b06e5f8fa841c3c00d990f [file] [log] [blame]
// 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