Xilinx
HLS
Block Preview

Introduction

The NCO (Numerically Controlled Oscillator) block generates high-precision periodic waveforms using the phase accumulator technique. This is a fundamental building block for Direct Digital Synthesis (DDS) applications.

The NCO supports multiple waveform types (sine, cosine, ramp, triangle, square, sawtooth) with configurable output resolution, frequency precision, and phase offset.

Pin Description

PERIOD Input 32/64 bit BIT VECTOR
Waveform period in clock cycles. Format depends on the “Period format” property. Output frequency = CLK frequency / PERIOD. Bus width: 32 or 64 bits depending on format.
Default: Must be connected
PHASE Input 16 bit BIT VECTOR

Phase offset (unsigned 16-bit). Adds a constant phase shift to the output waveform.

  • 0x0000 = 0°
  • 0x4000 = 90°
  • 0x8000 = 180°
  • 0xC000 = 270°
DUTY Input 16 bit BIT VECTOR

Duty cycle control (unsigned 16-bit). Used for TRIANGLE and SQUARE waveforms.

  • 0x0000 = defaults to 50%
  • 0x8000 = 50%
  • 0xFFFF = ~100%
SYMMETRY Input 16 bit BIT VECTOR
NOT IMPLEMENTED - reserved. The pin is present on the symbol and wired through to the IP, but no waveform reads it: TRIANGLE and SQUARE take their asymmetry from DUTY and every other waveform is symmetric by construction. Whatever is connected here has no effect on the output. Leave it unconnected (it then reads as a constant zero). The pin is kept on the symbol so that existing designs that wire it keep working.
CLK Input 1 bit BIT
System clock input. All operations are synchronous to this clock. Default: Board acquisition clock.
Default: Default Board Clock
RESET Input 1 bit BIT
Synchronous reset input. Resets the phase accumulator to zero. Default: Global reset.
Default: Default Board Reset
OUT Output 8-32 bit BIT VECTOR
Waveform output. Bit width configured by “Output bits” property (8-32 bits). Signed or unsigned based on “Output sign” property.

Properties

Property window

Output bits OutputBits

Number of bits of the output signal

Number of bits of the output signal. Range: 8 to 32, default 16.

Default: 16

Range: 8 – 32

Accumulator bits AccumulatorBits

Width of the internal phase accumulator register. Does NOT change the frequency resolution: the increment is always a multiple of 2^(bits-16), so the frequency grid is CLK/65536 for every setting and a wider accumulator only costs area. 32 is the cheapest fully functional choice.

Width of the internal phase accumulator register. It does NOT change the frequency resolution. The phase increment is always a multiple of 2^(bits-16), so the accumulator is effectively 16-bit and the frequency grid is f_clk/65536 for every setting; a wider accumulator only costs more area. Verified by regression: the same PERIOD stream gives a bit-identical output at 32 and at 64 bits. It does affect the LATENCY of the TRIANGLE waveform, and only that one: the slope divider is as wide as the accumulator plus 16 bits, so TRIANGLE costs 72 clock cycles at 32 bits and 105 at 64. Available values: 32, 40, 48, 56, 64, default 48 (32 is the cheapest fully functional choice).

Default: 48

Options: 32 40 48 56 64

Waveform type WaveformType

Select the type of waveform to generate

Type of waveform to generate. Available values: SINE, COSINE, RAMP, TRIANGLE, SQUARE, SAWTOOTH, default SINE.

Default: SINE

Options: SINE COSINE RAMP TRIANGLE SQUARE SAWTOOTH

Output sign OutputSign

Select signed or unsigned output

Output signal format. Available values: UNSIGNED, SIGNED, default SIGNED.

Default: SIGNED

Options: UNSIGNED SIGNED

Period format PeriodFormat

Scaling of the PERIOD input word (FIXED40.24 also widens the pin to 64 bit). The fractional bits are DISCARDED, not rounded: these formats give no sub-sample period resolution, they only let you connect a period already carried in a fixed-point word.

Scaling of the PERIOD input word (and, for FIXED40.24, its width: 64 bits instead of 32). The fractional bits are discarded, not rounded, so none of these formats gives sub-sample period resolution: they only let the block be fed a period that is already carried in a rescaled fixed-point word. Available values: UINT32, FIXED16.16, FIXED24.8, FIXED40.24, default UINT32.

Default: UINT32

Options: UINT32 FIXED16.16 FIXED24.8 FIXED40.24

Sine LUT Size LUTSize

Sine/Cosine lookup table size (larger = better resolution but more BRAM)

Sine/Cosine lookup table size. Larger values provide better waveform quality but use more BRAM. Available values: 256 (1.41° res), 512 (0.70° res), 1024 (0.35° res), 2048 (0.18° res), 4096 (0.09° res), 8192 (0.04° res), default 1024 (0.35° res).

Default: 1024 (0.35° res)

Options: 256 (1.41° res) 512 (0.70° res) 1024 (0.35° res) 2048 (0.18° res) 4096 (0.09° res) 8192 (0.04° res)

Usage

Phase Accumulator Principle

The NCO uses a phase accumulator to generate periodic waveforms. The phase accumulator is an N-bit register that increments by a fixed amount (phase increment) on each clock cycle:

$$ \phi[n] = \phi[n-1] + \Delta\phi \mod 2^N $$

where:

  • $\phi[n]$ is the current phase
  • $\Delta\phi$ is the phase increment
  • $N$ is the accumulator bit width

The phase accumulator naturally wraps around, producing a sawtooth-like phase ramp that drives the waveform generation.


Frequency Control

PERIOD is the number of clock cycles in one output period, so the nominal output frequency is

$$ f_{out} \simeq \frac{f_{clk}}{\text{PERIOD}} $$

The block does not use PERIOD directly. It converts it into a phase increment on a fixed 16-bit grid, one turn being 65536 units:

$$ \Delta\phi = \left\lfloor \frac{65536}{\text{PERIOD}} \right\rfloor \cdot 2^{N-16} $$

where $N$ is the accumulator bit width (32-64 bits). The frequency actually realised is therefore

$$ f_{out} = f_{clk} \cdot \frac{\left\lfloor 65536/\text{PERIOD} \right\rfloor}{65536} $$

which equals $f_{clk}/\text{PERIOD}$ exactly only when PERIOD divides 65536 (2, 4, 8, 16, 32, …, 1024, …, 65536 - PERIOD = 1 is the one exception, see below, because an increment of a whole turn wraps to zero). Example measured on the block: PERIOD = 20 gives an increment of $\lfloor 65536/20 \rfloor = 3276$ instead of 3276.8, i.e. a realised period of $65536/3276 = 20.005$ samples - right to 0.025 % but drifting by one sample every 4000.


Frequency Resolution

The frequency grid does NOT depend on “Accumulator bits”.

Every increment is a multiple of $2^{N-16}$, so the low $N-16$ bits of the accumulator are permanently zero: whatever “Accumulator bits” is set to, the accumulator behaves as a 16-bit one and the frequency grid is

$$ \Delta f = \frac{f_{clk}}{65536} $$

Sample rate Frequency step (any accumulator width)
100 MHz 1.526 kHz
250 MHz 3.815 kHz
1 GHz 15.26 kHz

This is verified by regression, not asserted: the same PERIOD stream produces a bit-identical output with “Accumulator bits” = 32 and with 64 (ci-test cases nco::freq_grid_acc32_sine / freq_grid_acc64_sine and the matching RAMP pair). “Accumulator bits” changes the width of the accumulator register only, i.e. the area the block costs; it buys no frequency resolution. 32 is therefore the cheapest fully functional choice – and for TRIANGLE it is also the fastest, because that waveform’s slope divider is as wide as the accumulator plus 16 bits (see Timing).

This block has no frequency word and no way to place an output frequency off the $f_{clk}/65536$ grid: if a finer grid is required, change the sample rate that feeds the block.


PERIOD = 0 and PERIOD = 1 stop the oscillator

PERIOD = 0 is illegal and the block substitutes 1. PERIOD = 1 means “one sample per output period”, i.e. a whole turn per sample: the increment is $\lfloor 65536/1 \rfloor = 65536$ units, which is exactly one turn and therefore wraps to zero. The phase stops advancing and the output holds the last value it had.

Expect a flat DC line for PERIOD = 0 and PERIOD = 1, not the fastest possible oscillation. The fastest usable setting is PERIOD = 2 (two samples per period, i.e. Nyquist).


Period Format

The PERIOD input can be written in several rescaled formats:

Format Total Bits Written word Integer period used
UINT32 32 period period
FIXED16.16 32 period × 65536 word » 16
FIXED24.8 32 period × 256 word » 8
FIXED40.24 64 period × 16777216 word » 24

The fractional bits are DISCARDED, not rounded. The core computes period = PERIOD >> frac_bits and uses that integer alone, so the fixed-point formats carry no sub-sample period resolution. FIXED16.16 / FIXED24.8 / FIXED40.24 behave exactly like UINT32 (UINT64 for FIXED40.24) fed with the rescaled word: they are a convenience for connecting a period that another part of the design already keeps in a fixed-point word, and nothing else. A written period of 20.8 samples is used as 20.

Sub-sample frequency control is not available on this block in any period format: see Frequency Resolution above for the grid that actually applies.


Waveform Types

The NCO can generate the following waveforms:

Waveform Description
SINE Sinusoidal wave using lookup table
COSINE Cosine wave (sine with 90° phase shift)
RAMP Linear ramp from minimum to maximum
TRIANGLE Triangular wave, rise/fall split set by DUTY
SQUARE Square wave with adjustable duty cycle
SAWTOOTH Inverted ramp from maximum to minimum

The SYMMETRY input is not read by any of them - see the SYMMETRY pin below.


Sine/Cosine Generation

For SINE and COSINE waveforms, the NCO uses a lookup table (LUT) containing pre-computed sine values. The phase accumulator’s upper bits index into the LUT.

LUT Size Angular Resolution
256 1.41°
512 0.70°
1024 0.35°
2048 0.18°
4096 0.09°
8192 0.04°

Larger LUTs provide better waveform quality (lower spurious content) but consume more BRAM.


Duty Cycle Control

For TRIANGLE and SQUARE waveforms, the DUTY input controls the symmetry:

  • SQUARE: DUTY determines the HIGH time percentage
  • TRIANGLE: DUTY determines the rising edge percentage

The DUTY input is a 16-bit unsigned value where:

  • 0x0000 = 0% (falls back to 50%)
  • 0x8000 = 50%
  • 0xFFFF = 100%

There is no second symmetry control: the SYMMETRY pin is accepted and ignored.


Phase Offset

The PHASE input adds a constant phase offset to the output:

$$ \phi_{total} = \phi_{acc} + \phi_{offset} $$

The PHASE input is a 16-bit unsigned value representing the phase in the range [0, 2π):

  • 0x0000 = 0°
  • 0x4000 = 90°
  • 0x8000 = 180°
  • 0xC000 = 270°

Output Format

The output can be configured as:

  • Signed: Output ranges from $-(2^{N-1})$ to $(2^{N-1}-1)$
  • Unsigned: Output ranges from 0 to $(2^N-1)$

where N is the output bit width (8-32 bits).

For SINE and COSINE the table is 16 bit whatever N is, so the amplitude is rescaled, never re-tabulated: N above 16 shifts the table word up (the low N-16 bits are always zero, there is no interpolation) and N below 16 shifts it down, keeping the sign. The shift down is arithmetic, i.e. it rounds towards minus infinity, so with N = 12 the peak is 32767 » 4 = +2047 while the trough is -2048: the negative half of the wave sits exactly one count below the mirror of the positive half. The phase-mapped waveforms (RAMP, TRIANGLE, SQUARE, SAWTOOTH) take the top N bits of their phase word instead, so for them a narrow output is only a coarser quantisation.


Timing

The block is fully pipelined: one new output sample on every clock cycle (II = 1). The input-to-output latency is not a small constant: it is set by the HLS schedule of the pipelined 65536/PERIOD divider, and for TRIANGLE by a second divider on top of it.

Measured on the generated RTL (vitis_hls 2020.2, part xc7a35t, 10 ns target clock, OUT 16 bit, 1024-entry LUT) by stepping PHASE by half a turn and counting the clocks to the first different output word:

Waveform Latency (clock cycles)
SINE, COSINE 22
RAMP, SQUARE, SAWTOOTH 21
TRIANGLE 72 / 81 / 89 / 97 / 105 for “Accumulator bits” 32 / 40 / 48 / 56 / 64

The period format and the output width change none of them. TRIANGLE is the one waveform whose latency grows with “Accumulator bits”: its slope divider is as wide as the accumulator plus 16 bits, so it costs about 8 more pipeline stages for every 8 accumulator bits. Picking 32 instead of the default 48 therefore saves 17 clock cycles of latency and the area of a 16-bit-wider divider, with no effect whatsoever on the waveform (the extra accumulator bits are always zero). For every other waveform the accumulator width is free.

Treat these as the numbers for the stated conditions: the exact depth is chosen by HLS from the target clock period and the FPGA part, so a faster clock or a different device can shift them by a cycle or two. The symbol badge declares the SINE/COSINE value for a scalar NCO; the TM twin is one cycle longer because it publishes its output through an extra register.

Latency only delays the waveform in time; because the oscillator is free-running it does not affect the frequency, and a constant delay on a periodic signal is indistinguishable from a phase offset. It matters only when the NCO output has to stay aligned with another path in the design.

Resources & Timing

  • Latency: 22 clock cycles for SINE/COSINE, 21 for RAMP/SQUARE/SAWTOOTH, 72 to 105 for TRIANGLE depending on the accumulator width (72 at 32 bits, 89 at the default 48, 105 at 64) – measured on the generated RTL, vitis_hls 2020.2, part xc7a35t, 10 ns clock; set by the HLS schedule of the 65536/PERIOD divider plus, for TRIANGLE, the accumulator-wide slope divider, so clock- and part-dependent

  • Throughput: 1 sample per clock cycle (II=1)

HLS-based implementation. Resource usage varies with LUT size and accumulator width; the accumulator width changes area only, never the frequency resolution.