/* * 3signal.v * * vim: ts=4 sw=4 * * Copyright (C) 2025 Krzysztof Skrzynecki, Jakub Duchniewicz * SPDX-License-Identifier: TODO: */ `default_nettype none module continous_pwm_gen#( parameter WIDTH = 16 ) ( input wire nrst, clk, input [WIDTH-1:0] period, input [WIDTH-1:0] delay, output wire [0:0] last_tick, output wire [0:0] mid_tick, output reg [0:0] pwm_out ); reg [WIDTH-1:0] counter; wire [WIDTH-1:0] next_cnt=counter+1; wire [WIDTH-1:0] last_avail_cnt=period-1; // Counter logic always_ff @(posedge clk or negedge nrst) begin if (!nrst) begin counter <= 0; pwm_out <= 0; end else begin if(counter >= last_avail_cnt) begin counter <= 0; end else begin counter <= next_cnt; end if ((next_cnt=last_avail_cnt)) begin pwm_out <= 0; end else begin pwm_out <= 1; end end end assign last_tick = (next_cnt>=period); assign mid_tick = ((next_cnt)==(period>>1)); endmodule module single_shot_gen#( parameter WIDTH = 16 )( input wire nrst, clk, input wire trigger, input [WIDTH-1:0] delay, input [WIDTH-1:0] duty, output reg [0:0] pwm_out ); reg [WIDTH-1:0] counter; reg [0:0] is_counting; wire [WIDTH-1:0] next_cnt=counter+1; wire [WIDTH-1:0] period=delay+duty; //wire [WIDTH-1:0] last_avail_cnt=period-1; always_ff @(posedge clk or negedge nrst) begin if (!nrst) begin counter <= 0; is_counting <= 0; end else begin if (is_counting) begin if(counter+1 >= period) begin counter <= 0; is_counting <= 0; pwm_out <= 0; end else begin counter <= next_cnt; if (next_cnt>=delay) begin pwm_out <= 1; end else begin pwm_out <= 0; end end end else begin if (trigger) begin is_counting <= 1; if ((delay==0) && (duty!=0)) begin pwm_out <= 1; end end end end end endmodule module phase_delay#( parameter WIDTH = 16, parameter FORWARD_DATA_WIDTH = 16 )( input wire nrst, clk, input wire in_trig, input [WIDTH-1:0] delay, input [FORWARD_DATA_WIDTH-1:0] in_data_fwd, output wire out_trig, output reg [FORWARD_DATA_WIDTH-1:0] out_data_fwd ); reg [WIDTH-1:0] counter; reg [0:0] is_counting; reg [WIDTH-1:0] delay_latched; always_ff @(posedge clk or negedge nrst) begin if (!nrst) begin counter <= 0; is_counting <=0; delay_latched <=0; end else begin if (is_counting) begin if ((counter+1) >= delay_latched) begin counter <= 0; is_counting <= 0; end else begin counter <= counter+1; end end else begin if (in_trig) begin is_counting <= 1; out_data_fwd <= in_data_fwd; delay_latched <= delay; end end end end assign out_trig=((counter+1)>=delay) && is_counting; endmodule module pulse_train_gen#( parameter WIDTH = 16, parameter PULSE_COUNTER_WIDTH = 16 )( input wire nrst, clk, input wire trigger, input [PULSE_COUNTER_WIDTH-1:0] npuls, input [WIDTH-1:0] period, input [WIDTH-1:0] duty, output reg [0:0] pwm_out ); reg [WIDTH-1:0] counter; reg [0:0] is_counting; reg [PULSE_COUNTER_WIDTH-1:0] remaining_pulses; reg [WIDTH-1:0] period_local; reg [WIDTH-1:0] duty_local; wire [WIDTH-1:0] next_cnt = counter+1; always_ff @(posedge clk or negedge nrst) begin if (!nrst) begin counter <= 0; is_counting <= 0; pwm_out <=0; end else begin if (is_counting) begin if(next_cnt >= period) begin counter <= 0; if (remaining_pulses > 0) begin remaining_pulses <= remaining_pulses-1; pwm_out <= 1; end else begin pwm_out <= 0; is_counting <= 0; end end else begin counter <= next_cnt; if (next_cnt>=duty) begin pwm_out <= 0; end else begin pwm_out <= 1; end end end else begin if (trigger) begin if ((period>0) && (duty!=0) && (npuls>0)) begin pwm_out <= 1; remaining_pulses <= npuls-1; is_counting <= 1; counter <= 0; period_local <= period; duty_local <= duty; end end end end end endmodule typedef enum logic [1:0] { ODD_TRAIN_FORCE_OFF, ODD_TRAIN_ENA_CONTROL, ODD_TRAIN_FORCE_ON } odd_train_flag_t; module three_signal#( parameter FAST_PWM_WIDTH=8, parameter PULSE_COUNTER_WIDTH=8, parameter SLOW_PWM_WIDTH=14 )( input wire nrst, clk, input [SLOW_PWM_WIDTH-1:0] period1, input [SLOW_PWM_WIDTH-1:0] delay1, input [SLOW_PWM_WIDTH-1:0] duty2, input [SLOW_PWM_WIDTH-1:0] delay2, input [FAST_PWM_WIDTH-1:0] period3, input [FAST_PWM_WIDTH-1:0] duty3, input [SLOW_PWM_WIDTH-1:0] delay3,//delay is wrt slow pwm, thus longer bit length input [PULSE_COUNTER_WIDTH-1:0] npuls3, input /*odd_train_flag_t*/ wire [1:0] odd_train_flag, input wire ena_odd_out3, output reg Out1, output reg Out2, output reg Out3 ); wire trigger_next_cycle; wire trigger_even_cycle; wire trigger_odd_cycle; wire [SLOW_PWM_WIDTH-1:0] delay3_part1; wire [SLOW_PWM_WIDTH-1:0] delay3_part234; assign delay3_part234 = delay3>>2; assign delay3_part1 = (delay3<4) ? 0 : (delay3 - (delay3_part234*3)); continous_pwm_gen #(.WIDTH(SLOW_PWM_WIDTH)) pwm1( .nrst(nrst), .clk(clk), .period(period1), .delay(delay1), .last_tick(trigger_next_cycle), .mid_tick(trigger_even_cycle), .pwm_out(Out1) ); single_shot_gen #(.WIDTH(SLOW_PWM_WIDTH)) pwm2( .nrst(nrst), .clk(clk), .trigger(trigger_next_cycle), .delay(delay2), .duty(duty2), .pwm_out(Out2) ); wire trigger_delay_1_to_2; wire trigger_delay_2_to_3; wire trigger_delay_3_to_4; wire trigger_delay_4_to_pulse_train; localparam FORWARD_DATA_WIDTH = SLOW_PWM_WIDTH + PULSE_COUNTER_WIDTH + FAST_PWM_WIDTH + FAST_PWM_WIDTH; localparam DELAY_BITS_POS = PULSE_COUNTER_WIDTH + FAST_PWM_WIDTH + FAST_PWM_WIDTH; wire [FORWARD_DATA_WIDTH-1:0] data_1_to_2; wire [FORWARD_DATA_WIDTH-1:0] data_2_to_3; wire [FORWARD_DATA_WIDTH-1:0] data_3_to_4; wire [FORWARD_DATA_WIDTH-1:0] data_4_to_gen; assign trigger_odd_cycle = (odd_train_flag == ODD_TRAIN_ENA_CONTROL) ? trigger_next_cycle && ena_odd_out3 : (odd_train_flag == ODD_TRAIN_FORCE_ON) ? trigger_next_cycle : 0; wire [FAST_PWM_WIDTH-1:0] period3_gen; wire [FAST_PWM_WIDTH-1:0] duty3_gen; wire [PULSE_COUNTER_WIDTH-1:0] npuls3_gen; assign duty3_gen = data_4_to_gen[FAST_PWM_WIDTH-1:0]; assign period3_gen = data_4_to_gen[FAST_PWM_WIDTH+FAST_PWM_WIDTH-1:FAST_PWM_WIDTH]; assign npuls3_gen = data_4_to_gen[FAST_PWM_WIDTH+FAST_PWM_WIDTH+PULSE_COUNTER_WIDTH-1:FAST_PWM_WIDTH+FAST_PWM_WIDTH]; phase_delay #(.WIDTH(SLOW_PWM_WIDTH),.FORWARD_DATA_WIDTH(FORWARD_DATA_WIDTH)) pd_1of4( .nrst(nrst), .clk(clk), .in_trig(trigger_odd_cycle | trigger_even_cycle), .delay(delay3_part1), .in_data_fwd({delay3_part234, npuls3, period3, duty3}), .out_trig(trigger_delay_1_to_2), .out_data_fwd(data_1_to_2) ); phase_delay #(.WIDTH(SLOW_PWM_WIDTH),.FORWARD_DATA_WIDTH(FORWARD_DATA_WIDTH)) pd_2of4( .nrst(nrst), .clk(clk), .in_trig(trigger_delay_1_to_2), .delay(data_1_to_2[DELAY_BITS_POS+SLOW_PWM_WIDTH-1:DELAY_BITS_POS]), .in_data_fwd(data_1_to_2), .out_trig(trigger_delay_2_to_3), .out_data_fwd(data_2_to_3) ); phase_delay #(.WIDTH(SLOW_PWM_WIDTH),.FORWARD_DATA_WIDTH(FORWARD_DATA_WIDTH)) pd_3of4( .nrst(nrst), .clk(clk), .in_trig(trigger_delay_2_to_3), .delay(data_2_to_3[DELAY_BITS_POS+SLOW_PWM_WIDTH-1:DELAY_BITS_POS]), .in_data_fwd(data_2_to_3), .out_trig(trigger_delay_3_to_4), .out_data_fwd(data_3_to_4) ); phase_delay #(.WIDTH(SLOW_PWM_WIDTH),.FORWARD_DATA_WIDTH(FORWARD_DATA_WIDTH)) pd_4of4( .nrst(nrst), .clk(clk), .in_trig(trigger_delay_3_to_4), .delay(data_3_to_4[DELAY_BITS_POS+SLOW_PWM_WIDTH-1:DELAY_BITS_POS]), .in_data_fwd(data_3_to_4), .out_trig(trigger_delay_4_to_pulse_train), .out_data_fwd(data_4_to_gen) ); pulse_train_gen #(.WIDTH(FAST_PWM_WIDTH),.PULSE_COUNTER_WIDTH(PULSE_COUNTER_WIDTH)) pwm3( .nrst(nrst), .clk(clk), .trigger(trigger_delay_4_to_pulse_train), .npuls(npuls3_gen), .period(period3_gen), .duty(duty3_gen), .pwm_out(Out3) ); endmodule