Fully pipelined, multi-computation CORDIC core in VHDL-2008.
Supports rotation and vectoring modes, verified with Python-generated test vectors and simulated with GHDL.
This project implements a CORDIC (COordinate Rotation DIgital Computer) algorithm in VHDL-2008, structured as a true synchronous pipeline.
It computes trigonometric and hyperbolic functions using only shifts and additions — no multipliers required in the iteration kernel.
Two operating modes are supported:
| Mode | mode pin |
Function |
|---|---|---|
| Rotation | '0' |
Rotates input vector (x1, y1) by angle β |
| Vectoring | '1' |
Computes magnitude and phase of (x1, y1) |
Key design properties:
- Pure pipeline — no FSM, no handshake stalls
- One new computation can be launched every clock cycle
- Up to
N_ITERcomputations in-flight simultaneously - CORDIC gain compensation (
K ≈ 0.6073) applied in rotation mode - Angle pre-folding into
[−π/2, π/2]convergence domain - Self-checking testbench with configurable tolerance thresholds
┌──────────────────────────────────────────────────────┐
x1, y1, β ──>│ cordic.vhd (top-level + K pre-scaler) │
mode, start │ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ cordic_processor.vhd (pipeline controller) │ │
│ │ │ │
│ │ Stage 0 ──> kernel_0 ──> kernel_1 ──> ... ──> │ │
│ │ (DFF) (DFF) (DFF) kernel_N │ │
│ │ │ │
│ │ valid_sr: start │ sr(0) │ ... │ sr(N) = done │ │
│ └─────────────────────────────────────────────────┘ │
│ │
x2, y2, z2 <──────────────────────────────────────────────────────── │
done └──────────────────────────────────────────────────────┘
Each cordic_kernel performs one CORDIC micro-rotation:
x_{i+1} = x_i − d_i · y_i · 2^{−i}
y_{i+1} = y_i + d_i · x_i · 2^{−i}
z_{i+1} = z_i − d_i · atan(2^{−i})
where d_i = +1 or −1 depending on the mode and the sign of z_i (rotation) or y_i (vectoring).
.
├── src/
│ ├── cordic.vhd # Top-level wrapper (K pre-scaler + port map)
│ ├── cordic_processor.vhd # Pipeline controller + ATAN ROM + valid SR
│ └── cordic_kernel.vhd # Single CORDIC micro-rotation stage (DFF)
├── tb/
│ └── cordic_tb_with_file.vhd # Self-checking testbench (file-driven)
├── python/
│ └── cordic_testdata_gen.py # Reference vector generator
├── work/
│ ├── build/ # GHDL compiled objects (generated)
│ ├── data/ # Test vectors (generated)
│ └── waveform/ # VCD output (generated)
└── Makefile
| Generic | Entity | Default | Description |
|---|---|---|---|
N_BITS_VECTOR |
all | 32 |
Data path width for X and Y (bits) |
N_BITS_ANGLE |
all | 18 |
Angle accumulator width (bits) |
N_ITER |
cordic, cordic_processor |
15 |
Pipeline depth (CORDIC iterations) |
CLK_PERIOD |
testbench | 20 |
Testbench slow-clock half-period (ns) |
DATA_FILE_M0 |
testbench | — | Absolute path to Mode 0 test vector file |
DATA_FILE_M1 |
testbench | — | Absolute path to Mode 1 test vector file |
| Port | Direction | Width | Description |
|---|---|---|---|
clk |
in | 1 | System clock |
rst |
in | 1 | Synchronous active-high reset |
x1 |
in | N_BITS_VECTOR |
Input X (real part) |
y1 |
in | N_BITS_VECTOR |
Input Y (imaginary part) |
mode |
in | 1 | '0' = rotation, '1' = vectoring |
beta |
in | N_BITS_ANGLE |
Input angle (fixed-point) |
start |
in | 1 | One-cycle pulse to launch a computation |
x2 |
out | N_BITS_VECTOR+1 |
Output X (sign-extended) |
y2 |
out | N_BITS_VECTOR+1 |
Output Y (sign-extended) |
z2 |
out | N_BITS_ANGLE |
Output angle / phase |
done |
out | 1 | Asserted for one cycle when result is valid |
All angles are normalised to [−π, π) and stored as signed integers where:
LSB = π / 2^(N_BITS_ANGLE − 2)
For N_BITS_ANGLE = 18: 1 LSB ≈ 1.2 × 10⁻⁵ rad ≈ 0.00069°
Cycle: 0 1 2 3 ... N_ITER N_ITER+1
│ │ │ │ │ │
start ────┤ │ │ │ │ │
│ │ │ │ │ │
Stage 0 ╔══════╗ │ │ │ │
(DFF) ║ latch║ │ │ │ │
╚══════╝ │ │ │ │
Kernel 0 ╔══════╗ │ │ │
║ DFF ║ │ │ │
╚══════╝ │ │ │
Kernel 1 ╔══════╗ │ │
║ DFF ║ │ │
╚══════╝ │ │
... │ │
Kernel N-1 ╔═════╗ │
║ DFF ║ │
╚═════╝ │
done ────────────────────────────────────────────> ┤
x2/y2/z2 valid ──────────────────────────────────> ┤
Total latency = N_ITER + 1 clock cycles from start to done.
At N_ITER = 15: 16 cycles.
| Tool | Version tested | Purpose |
|---|---|---|
| GHDL | ≥ 3.0 | VHDL simulation |
| GTKWave | ≥ 3.3 | Waveform viewer |
| Python | ≥ 3.8 | Test vector generation |
| GNU Make | any | Build automation |
| Git Bash | Windows only | Shell environment |
Windows note: GHDL on Windows uses the
mcodebackend and does not produce a standalone executable. The Makefile usesghdl -rfor simulation andcygpath -mfor path conversion.
# Clone the repository
git clone https://github.com/myotochie/cordic.git
cd cordic
# Generate test vectors, compile, elaborate, and simulate
make run
# Open the waveform (requires GTKWave)
make view_waveform| Target | Description |
|---|---|
make run |
Full flow: setup → generate → compile → simulate (default) |
make setup |
Create work/ directory tree |
make generate_data |
Run Python script to produce test vectors |
make compile |
Analyse and elaborate VHDL sources with GHDL |
make view_waveform |
Open wave.vcd in GTKWave |
make clean |
Remove all generated files under work/ |
make rebuild |
clean + run |
make paths |
Print resolved POSIX and Windows paths (debug) |
Key Makefile parameters (edit at the top of Makefile):
N_SAMPLES := 100 # Number of test vectors per mode
CLK_PERIOD := 20 # Testbench slow-clock half-period (ns)
STOP_TIME := 60000nspython cordic_testdata_gen.py
│
├── work/data/cordic_m0_testdata.txt (rotation vectors)
└── work/data/cordic_m1_testdata.txt (vectoring vectors)
│
▼
ghdl -a (analyse sources)
ghdl -e (elaborate, with -g overrides)
ghdl -r (simulate → wave.vcd + report)
│
▼
cordic_tb_with_file.vhd
├── MODE 0: checks |x_got − x_ref| ≤ 50 and |y_got − y_ref| ≤ 50
└── MODE 1: checks |z_got − z_ref| ≤ 40
│
▼
report "Simulation finished. Total lines: N, Total errors: E"
A successful run produces zero warnings and ends with:
cordic_tb_with_file.vhd:...: report "Finished MODE 0"
cordic_tb_with_file.vhd:...: report "Simulation finished. Total lines: 799, Total errors: 0"
cordic_tb_with_file.vhd:...: report "Finished MODE 1"
cordic_tb_with_file.vhd:...: report "Simulation finished. Total lines: 799, Total errors: 0"
Generated by python/cordic_testdata_gen.py.
All values are signed integers in the fixed-point encoding of the DUT.
cordic_m0_testdata.txt — rotation mode (5 columns):
xi yi beta xo_ref yo_ref
cordic_m1_testdata.txt — vectoring mode (6 columns):
xi yi beta xo_ref yo_ref zo_ref
- The
cordic.vhdinput pre-processor is combinatorial — glitches onmode,x1, ory1propagate immediately to the processor inputs. This is harmless as long as inputs are stable beforestartis asserted. - The
cordic_kerneloutput registers have no reset. The pipeline guarantees thatenais never asserted before valid data has propagated, so uninitialised register values never reach the outputs. - Only the mcode backend of GHDL has been tested (Windows). On Linux/macOS with the GCC or LLVM backend,
ghdl -rmay produce a native executable; the Makefile'sghdl -rinvocation remains valid in all cases.
Each VHDL source file is commented in Doxygen format.
To generate HTML documentation:
doxygen -g # Generate default Doxyfile
# Edit Doxyfile: set OPTIMIZE_OUTPUT_VHDL = YES
# set INPUT = src/ tb/
doxygen Doxyfile
# Open html/index.html