├── README.md ├── programmable_delay.v └── programmable_delay_line.v /README.md: -------------------------------------------------------------------------------- 1 | # programmable-delay-line 2 | 3 | A resource-efficient Verilog implementation of an asynchronous, adjustable delay line. 4 | 5 | Asynchronous delay lines are implemented by wiring pairs of inverter gates in series. 6 | Pairs of inverter gates (instead of single buffers) to correct for the possibility of asymmetry between rise and fall 7 | times of FPGA logic elements (LEs). For example, if the LEs tend to have a fast fall time than rise time, falling edges 8 | will propagate through a LE faster than rising edges, causing pulses to shrink. Inverter gates turn rising edges into 9 | falling edges and vice-versa, which corrects somewhat for this effect. 10 | 11 | The actual amount of time delay that is implemented is highly hardware-dependent. I typically use Altera Cyclone IV FPGAs, 12 | and have measured the average response time of a single logic element to be about 300 ps. So the total delay of my lines 13 | is approximately 2 * N * (.3 ns). Keep in mind that precise control (i.e. below the order of 100 ps) 14 | of the amount of delay is an extremely difficult task. 15 | 16 | ## Files 17 | 18 | - programmable_delay.v: A module that instantiates adjustable delay lines 19 | - programmable_delay_line.v: A top-level module for a simple test project using some switches 20 | 21 | ## Parameters 22 | 23 | All parameters are mandatory and have no defaults. 24 | 25 | - nominal_delay: "y intercept" of the delay, i.e. the number of delay elements when code = 0 26 | - delta_delay: "slope" of the delay, i.e. the number of delay elements the line is increased by when code is increased 27 | - N: The number of possible combinations. Should be a power of 2. 28 | - log2_N: log2(N) 29 | 30 | ## Arguments 31 | 32 | in: input, single wire. The signal you want to delay 33 | code: input, array of log2_N wires. A binary value that selects the amount of delay 34 | out: output, single wire. The input signal, delayed by the desired amount 35 | 36 | The total amount of delay increases linearly with code, i.e. 37 | 38 | total_delay = nominal_delay + delta_delay * code; code in [0,N-1] 39 | -------------------------------------------------------------------------------- /programmable_delay.v: -------------------------------------------------------------------------------- 1 | 2 | module programmable_delay(in,code,out); 3 | 4 | // total delay = nominal_delay + delta_delay * x 5 | // for x in [0, N-1] 6 | parameter nominal_delay, delta_delay, N, log2_N; 7 | 8 | input in /*synthesis keep*/; 9 | input [log2_N-1:0] code; 10 | output out /*synthesis keep*/; 11 | 12 | //synthesis keep = 1; 13 | wire [N-1:0] mux_output /* synthesis keep */; 14 | wire [2*delta_delay*(N-1)-1:0] internal_wire /* synthesis keep */; 15 | 16 | // nested generate loops = ugly code 17 | assign mux_output[N-1] = in; 18 | genvar i, j; 19 | generate 20 | for (i = 0; i < (N-1); i = i+1) 21 | begin: outer_loop 22 | assign internal_wire[delta_delay*2*i] = ~( (code == i) ? in : mux_output[i+1] ); 23 | for (j = 1; j < 2*delta_delay; j = j+1) 24 | begin: inner_loop 25 | assign internal_wire[delta_delay*2*i+j] = ~internal_wire[delta_delay*2*i+j-1]; 26 | end 27 | assign mux_output[i] = internal_wire[delta_delay*2*i+2*delta_delay-1]; 28 | end 29 | endgenerate 30 | 31 | 32 | assign out = mux_output[0]; 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /programmable_delay_line.v: -------------------------------------------------------------------------------- 1 | module programmable_delay_line(SW, SMA_CLKOUT); 2 | 3 | // total delay = nominal_delay + delta_delay * x 4 | // for x in [0, N-1] 5 | parameter nominal_delay = 0; 6 | parameter delta_delay = 5; 7 | parameter N = 16; 8 | parameter log2_N = 4; 9 | 10 | input [log2_N-1:0] SW; 11 | output SMA_CLKOUT; 12 | 13 | wire [log2_N-1:0] code; 14 | wire pre_delayed /* synthesis keep */; 15 | wire post_delayed /* synthesis keep */; 16 | 17 | assign code[log2_N-1:0] = SW[log2_N-1:0]; 18 | assign pre_delayed = ~post_delayed; 19 | assign SMA_CLKOUT = post_delayed; 20 | 21 | programmable_delay #(.nominal_delay(nominal_delay), .delta_delay(delta_delay), .N(N), .log2_N(log2_N)) (pre_delayed, code[log2_N-1:0], post_delayed); 22 | 23 | endmodule 24 | --------------------------------------------------------------------------------