|
@@ -0,0 +1,349 @@
|
|
|
|
+/*
|
|
|
|
+ * 3signal.v
|
|
|
|
+ *
|
|
|
|
+ * vim: ts=4 sw=4
|
|
|
|
+ *
|
|
|
|
+ * Copyright (C) 2025 Krzysztof Skrzynecki, Jakub Duchniewicz <j.duchniewicz@gmail.com>
|
|
|
|
+ * 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<delay) || (counter>=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
|
|
|
|
+
|