Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
# QubitPulseGenerator
# QubitPulseGenerator

- Run simulation (Questa or Vivado xsim): `cd scripts && vsim -c -do sim.do` or `vivado -mode batch -source sim.do`.
- Create Vivado project (XC7A100T): `create_project pulse_gen ./build -part xc7a100tcsg324-1; add_files ../rtl/pulse_gen.sv; add_files -fileset constrs_1 ../constraints/pulse_gen.xdc`.
- Run implementation: `launch_runs impl_1 -to_step write_bitstream; wait_on_run impl_1`.
- Generate timing report: `report_timing_summary -delay_type max -report_unconstrained -max_paths 10 -file timing_summary.rpt`.
- Verify in `timing_summary.rpt` that `WNS >= 0` and reported Fmax is greater than 100 MHz.
3 changes: 3 additions & 0 deletions constraints/pulse_gen.xdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
create_clock -name clk -period 10.000 [get_ports clk]
set_property PACKAGE_PIN E3 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
45 changes: 45 additions & 0 deletions rtl/pulse_gen.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module pulse_gen #(
parameter int WIDTH_BITS = 8,
parameter int PERIOD_BITS = 16
) (
input logic clk,
input logic rst_n,
input logic enable,
input logic [WIDTH_BITS-1:0] width,
input logic [PERIOD_BITS-1:0] period,
output logic pulse,
output logic busy
);

logic [PERIOD_BITS-1:0] count;
logic [PERIOD_BITS-1:0] width_eff;

always_comb begin
if (width >= period)
width_eff = period;
else
width_eff = {{(PERIOD_BITS-WIDTH_BITS){1'b0}}, width};
end
Comment on lines +17 to +22

always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
count <= '0;
pulse <= 1'b0;
busy <= 1'b0;
end else if (!enable || (period == '0) || (width == '0)) begin
count <= '0;
pulse <= 1'b0;
busy <= 1'b0;
end else begin
busy <= 1'b1;

if (count == (period - 1'b1))
count <= '0;
else
count <= count + 1'b1;

pulse <= (count < width_eff);
end
end

endmodule
12 changes: 12 additions & 0 deletions scripts/sim.do
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
if {[info commands vlog] ne ""} {
vlib work
vlog -sv ../rtl/pulse_gen.sv ../sim/tb_pulse_gen.sv
vsim -c tb_pulse_gen -do "run -all; quit -f"
} elseif {[info commands xvlog] ne ""} {
Comment on lines +1 to +5
file mkdir xsim
xvlog -sv ../rtl/pulse_gen.sv ../sim/tb_pulse_gen.sv
xelab tb_pulse_gen -s tb_pulse_gen_sim
xsim tb_pulse_gen_sim -runall
} else {
puts "No supported simulator commands found (vlog/vsim or xvlog/xelab/xsim)."
}
6 changes: 6 additions & 0 deletions sim/results.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Expected waveform summary (100MHz clock, 10ns period):
- During active-low reset: pulse=0, busy=0.
- width=1, period=2, enable=1: pulse alternates high/low every clock (10ns high, 10ns low), busy=1.
- enable->0: pulse drops to 0 immediately on next clock, busy=0, counter resets.
- width=255, period=65535, enable=1: pulse high for 255 cycles (2.55us), then low for 65280 cycles (652.8us), repeating.
- Reassert reset during run: pulse=0, busy=0, generation restarts from cycle 0 when enabled again.
99 changes: 99 additions & 0 deletions sim/tb_pulse_gen.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
`timescale 1ns/1ps

module tb_pulse_gen;
localparam int WIDTH_BITS = 8;
localparam int PERIOD_BITS = 16;

logic clk;
logic rst_n;
logic enable;
logic [WIDTH_BITS-1:0] width;
logic [PERIOD_BITS-1:0] period;
logic pulse;
logic busy;

int errors;

pulse_gen #(
.WIDTH_BITS(WIDTH_BITS),
.PERIOD_BITS(PERIOD_BITS)
) dut (
.clk(clk),
.rst_n(rst_n),
.enable(enable),
.width(width),
.period(period),
.pulse(pulse),
.busy(busy)
);

always #5 clk = ~clk;

task automatic expect_equal(input string tag, input bit got, input bit exp);
if (got !== exp) begin
$error("%s mismatch: got=%0b exp=%0b at t=%0t", tag, got, exp, $time);
errors++;
end
endtask
Comment on lines +32 to +37

task automatic verify_periodic(input int unsigned w, input int unsigned p, input int unsigned cycles);
int unsigned i;
for (i = 0; i < cycles; i++) begin
@(posedge clk);
expect_equal("busy", busy, (enable && (w != 0) && (p != 0)));
expect_equal("pulse", pulse, ((i % p) < ((w < p) ? w : p)));
end
Comment on lines +41 to +45
endtask

initial begin
clk = 1'b0;
rst_n = 1'b0;
enable = 1'b0;
width = '0;
period = '0;
errors = 0;

repeat (3) @(posedge clk);
expect_equal("reset pulse", pulse, 1'b0);
expect_equal("reset busy", busy, 1'b0);

rst_n = 1'b1;
@(posedge clk);

width = 8'd1;
period = 16'd2;
enable = 1'b1;
verify_periodic(1, 2, 12);

enable = 1'b0;
repeat (2) @(posedge clk);
expect_equal("disabled pulse", pulse, 1'b0);
expect_equal("disabled busy", busy, 1'b0);

width = 8'hFF;
period = 16'hFFFF;
enable = 1'b1;
verify_periodic(8'hFF, 16'hFFFF, 66000);

enable = 1'b0;
@(posedge clk);
expect_equal("toggle low pulse", pulse, 1'b0);
expect_equal("toggle low busy", busy, 1'b0);

enable = 1'b1;
verify_periodic(8'hFF, 16'hFFFF, 300);

rst_n = 1'b0;
@(posedge clk);
expect_equal("reset2 pulse", pulse, 1'b0);
expect_equal("reset2 busy", busy, 1'b0);
rst_n = 1'b1;

if (errors == 0)
$display("PASS: all checks passed");
else
$fatal(1, "FAIL: %0d checks failed", errors);

$finish;
end
endmodule
Loading