Browse Source

Port 3signal code and integrate to the top module.

Signed-off-by: Jakub Duchniewicz <j.duchniewicz@gmail.com>
Jakub Duchniewicz 3 tuần trước cách đây
mục cha
commit
bc60e00b90

+ 1 - 0
projects/riscv_usb/Makefile

@@ -12,6 +12,7 @@ PROJ_RTL_SRCS := $(addprefix rtl/, \
 	soc_spram.v \
 	soc_usb.v \
 	sysmgr.v \
+	3signal.v \
 )
 PROJ_SIM_SRCS := $(addprefix sim/, \
 	spiflash.v \

+ 23 - 2
projects/riscv_usb/data/top-icebreaker.pcf

@@ -17,8 +17,29 @@ set_io -nowarn uart_tx 9
 # Clock
 set_io -nowarn clk_in 35
 
-# Button
-set_io -nowarn btn 10
+# Buttons
+set_io -nowarn btn_n 10
+
+# GPIOs TODO: later connect Elekt keyboard (where plug the outputs in such case? RGB PMOD?
+set_io -nowarn out1 3
+set_io -nowarn out2 48
+set_io -nowarn out3 46
+
+# LEDs and Buttons (PMOD 2)
+set_io -nowarn led1       26
+set_io -nowarn led2       27
+set_io -nowarn led3       25
+set_io -nowarn led4       23
+set_io -nowarn led5       21
+set_io -nowarn btn_1       20
+set_io -nowarn btn_2       19
+set_io -nowarn btn_3       18
+
+set_io -nowarn led[0]     26
+set_io -nowarn led[1]     27
+set_io -nowarn led[2]     25
+set_io -nowarn led[3]     23
+set_io -nowarn led[4]     21
 
 # Leds
 set_io -nowarn rgb[0] 39

+ 349 - 0
projects/riscv_usb/rtl/3signal.v

@@ -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
+

+ 53 - 5
projects/riscv_usb/rtl/top.v

@@ -20,7 +20,7 @@ module top (
 	output wire spi_ram_cs_n,
 `endif
 
-	// USB
+	// USB TODO: remove later
 	inout  wire usb_dp,
 	inout  wire usb_dn,
 	output wire usb_pu,
@@ -29,10 +29,19 @@ module top (
 	input  wire uart_rx,
 	output wire uart_tx,
 
-	// Button
-	input  wire btn,
+	// Buttons (2 for now to test up and down)
+	input  wire btn_n,
+    input wire btn_1,
+    input wire btn_2,
 
-	// LED
+    // LEDs to blink to show that a value change has been registered?
+
+    // GPIOs for out signal
+    output wire out1,
+    output wire out2,
+    output wire out3,
+
+	// LED TODO: remove later
 	output wire [2:0] rgb,
 
 	// Clock
@@ -47,6 +56,10 @@ module top (
 	localparam integer WB_RW = WB_DW * WB_N;
 	localparam integer WB_MW = WB_DW / 8;
 
+    localparam integer FAST_PWM_WIDTH = 8;
+    localparam integer PULSE_COUNTER_WIDTH = 8;
+    localparam integer SLOW_PWM_WIDTH = 14;
+
 	genvar i;
 
 
@@ -72,6 +85,17 @@ module top (
 	wire clk_48m;
 	wire rst;
 
+    // 3 signal
+    wire [SLOW_PWM_WIDTH-1:0] period1;
+    wire [SLOW_PWM_WIDTH-1:0] delay1;
+    wire [SLOW_PWM_WIDTH-1:0] duty2;
+    wire [SLOW_PWM_WIDTH-1:0] delay2;
+    wire [FAST_PWM_WIDTH-1:0] period3;
+    wire [FAST_PWM_WIDTH-1:0] duty3;
+    wire [SLOW_PWM_WIDTH-1:0] delay3;
+    wire [PULSE_COUNTER_WIDTH-1:0] npuls3;
+    wire [1:0] odd_train_flag;
+    wire ena_odd_out3;
 
 	// SoC
 	// ---
@@ -191,6 +215,30 @@ module top (
 
 	assign wb_rdata[5] = 0;
 
+    // 3 Signal
+    // --------
+
+    three_signal #(
+        .FAST_PWM_WIDTH(FAST_PWM_WIDTH),
+        .PULSE_COUNTER_WIDTH(PULSE_COUNTER_WIDTH),
+        .SLOW_PWM_WIDTH(SLOW_PWM_WIDTH)
+    ) three_signal_I(
+        .nrst(~rst),
+        .clk(clk_48m),
+        .period1(period1),
+        .delay1(delay1),
+        .duty2(duty2),
+        .delay2(delay2),
+        .period3(period3),
+        .duty3(duty3),
+        .delay3(delay3),
+        .npuls3(npuls3),
+        .odd_train_flag(odd_train_flag),
+        .ena_odd_out3(ena_odd_out3),
+        .Out1(out1),
+        .Out2(out2),
+        .Out3(out3)
+    );
 
 	// Warm Boot
 	// ---------
@@ -216,7 +264,7 @@ module top (
 	) dfu_helper_I (
 		.boot_now(boot_now),
 		.boot_sel(boot_sel),
-		.btn_pad(btn),
+		.btn_pad(btn_n),
 		.btn_val(),
 		.rst_req(),
 		.clk(clk_24m),