Created
August 6, 2025 12:33
-
-
Save pavel-kirienko/7ccd1f7079f5c90dfdd03a29b36e10f5 to your computer and use it in GitHub Desktop.
A simple numerically controlled oscillator (NCO) in Verilog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// A numerically controlled oscillator (NCO) that outputs a sawtooth wave, whose frequency is a function of | |
/// clk rate and frequency_control_word, and the amplitude spans the range [0, 2**OUTPUT_WIDTH). | |
/// The output frequency is defined as: | |
/// | |
/// f_out = (f_clk * frequency_control_word) / (2**PHASE_ACCUMULATOR_WIDTH) | |
/// | |
/// Solve for frequency_control_word: | |
/// | |
/// frequency_control_word = ((2**PHASE_ACCUMULATOR_WIDTH) * f_out) / f_clk | |
/// | |
/// The phase of the output signal can be adjusted using phase_control_word, which is a value in the range | |
/// [0, 2**PHASE_ACCUMULATOR_WIDTH) that maps to [0, 2 pi). | |
/// | |
/// Both of the control words can be changed arbitrarily; changes take effect in the next cycle. | |
module nco #( | |
parameter OUTPUT_WIDTH = 8, ///< Larger values reduce phase noise. | |
parameter PHASE_ACCUMULATOR_WIDTH = 64 ///< Larger values reduce frequency error. | |
) | |
( | |
input wire clk, | |
input wire reset, | |
input wire [PHASE_ACCUMULATOR_WIDTH-1:0] frequency_control_word, | |
input wire [PHASE_ACCUMULATOR_WIDTH-1:0] phase_control_word, | |
output wire [OUTPUT_WIDTH-1:0] out | |
); | |
reg [PHASE_ACCUMULATOR_WIDTH-1:0] acc = 0; | |
wire [PHASE_ACCUMULATOR_WIDTH-1:0] acc_phased = acc + phase_control_word; | |
assign out = acc_phased[PHASE_ACCUMULATOR_WIDTH-1:PHASE_ACCUMULATOR_WIDTH-OUTPUT_WIDTH]; | |
always @(posedge clk or posedge reset) begin | |
if (reset) begin | |
acc <= 0; | |
end else begin | |
acc <= acc + frequency_control_word; | |
end | |
end | |
endmodule |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// iverilog -Wall -Wno-timescale -y. nco_tb.v && vvp a.out | |
/// Then open nco.vcd in GTK Wave or whatever. | |
`timescale 1ns/1ns | |
module nco_tb; | |
reg reset = 0; | |
initial begin | |
# 1 reset = 1; | |
# 2 reset = 0; | |
# 100 pcw = 32; | |
# 100 fcw = 4; | |
# 100 pcw = 16; | |
# 100 fcw = 8; | |
# 100 $finish; | |
end | |
reg clk = 0; | |
always begin | |
#1 clk = !clk; | |
end | |
reg [5:0] fcw = 1; | |
reg [5:0] pcw = 0; | |
wire [1:0] out; | |
nco #(2, 6) nco_it (clk, reset, fcw, pcw, out); | |
initial begin | |
$dumpfile("nco.vcd"); | |
$dumpvars(); | |
end | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment