Skip to content

Latest commit

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ck37-core

License: CERN OHL-S v2License: CC BY 4.0SimulationSynthesisTimingTargetFormer Lab

A soft-core FPGA replica of the Saab CK37 — the world's first airborne computer built with integrated circuits.

The CK37 was the central navigation and fire control computer of the Saab 37 Viggen, Sweden's Mach 2 multirole fighter. First flown in 1963, it was the first computer in the world to use first-generation integrated circuits in an airborne application. Nearly 200 units were delivered between 1970 and 1978. Some remained in active service until the early 2000s.

This project reconstructs the CK37 as a working FPGA soft-core, assembled from primary sources — including the official FMV maintenance manual Beskrivning CK37, Del 1 (1985-11-01) and Bengt Jiewertz's original design documentation. The goal is a functionally accurate replica: correct instruction set, correct number representation, correct I/O architecture — running original-class navigation software.

The end target is a fixed-wing drone with a CK37 soft-core as its navigation computer. The same algorithms that guided a Viggen at Mach 1.1 and 30 metres AGL are more than sufficient for autonomous flight.


Status

ComponentStatus
CPU core (Verilog)All bugs fixed — 25/25 tests passing
Instruction encodingConfirmed from FMV manual Bild 12/13
Memory modelVM/PM/EEPROM/PROM regions
Interrupt system6-level, vectors from Tabell 3
Clock interrupts2.864ms + 34.37ms generators
Analogue I/O bridgeMemory-mapped, channel table confirmed
Digital I/OSynthesisable (packed arrays, no dynamic range selects)
AssemblerOctal, Q1.25, full 26-bit encoding
Navigation kernel198 words — IRQ4/IRQ5 handlers, PID nav loop
FPGA synthesisClean — 1,978 LUT4, 12/12 EBR, ECP5-25F
Place and route85 MHz max (10 MHz target) — 8.5× timing margin
Hardware bring-upPending OrangeCrab flash

Architecture

The CK37 is a 26-bit fixed-point fractional computer (Q1.25 format), single-accumulator, with a 15-bit address space spanning up to 18432 words across four memory regions.

Machine parameters

ParameterValueSource
Word length26 bits + 2 parityFMV Del 1, Sida 13
Number formatQ1.25 signed fraction, range [−1, +1)Sida 12
Number baseOctal (10 octal digits per word)Sida 12
Clock2.860 MHzAppendix 2
Instructions48 basic, 4 formatsBild 11–14
Interrupts6 priority levelsTabell 3
Analogue I/O32 in + 32 out, sampled every 17msSida 16
Digital I/O450 binary signalsAppendix 3
Multiply time23.8 µs (two-shift method)Appendix 2
MTBF>200 hours flight operationAppendix 3

Memory map (octal addresses)

000000 – 003777 VM Variable Memory (RAM, read/write)
100000 – 177777 PM Permanent Memory (ROM, write-protected)
204000 – 314000 EEPROM
400000 – 404000 PROM (interrupt vectors)

In the 15-bit CPU address space: PM base = 15'h1000 (4096 decimal). PROM vectors at 0x4000 + level*2.

Instruction formats

Four formats confirmed from FMV manual Bild 11–14:

Halvords enadress [13 bits] pos 00-12
[0] [opcode 4b] [address 8b]
Helords enadress [26 bits] pos 00-25
[opcode 13b, pos 00-12] [address 13b, pos 13-25]
Helordsorder med operand [26 bits]
[opcode 10b] [irrel 3b] [operand sign] [operand 12b]
Helords tvåadress [26 bits] — GOTOPR only
[opcode 3b] [L address 10b] [M address 13b]
Stores return address at L, jumps to M

Bit layout: position 00 = MSB = IR[25], position 25 = LSB = IR[0]. IR[25] = 1 distinguishes full-word (26-bit) from half-word (13-bit) instructions.

Interrupt system (Tabell 3)

All addresses octal:

LevelTypeStore addressJump address
0Power off000000400000
1Power on000002400002
2Parity / write error000004400004
3Program load000006400006
4Clock 2.864 ms (~350 Hz)000010400010
5Clock 34.37 ms (~29 Hz)000012400012

The 2.864ms clock interrupt (8191 cycles at 2.860MHz — exactly 2¹³−1) drives the fast navigation update loop. The 34.37ms interrupt drives position integration and display updates.


Repository Structure

ck37-core/
├── rtl/
│ ├── ck37_cpu.v CPU core — 26-bit, Q1.25, 48-instruction ISA
│ ├── ck37_mem.v Memory — VM/PM/EEPROM/PROM, parity-guarded
│ ├── ck37_aio.v Analogue I/O bridge (32+32 channels, SPI)
│ ├── ck37_dio.v Digital I/O (450 bits, 35×13-bit words)
│ ├── ck37_clk_irq.v Clock interrupt generator (IRQ4 + IRQ5)
│ └── ck37_top.v Integration top-level (memory bus arbitration)
├── syn/
│ ├── ck37_syn_top.v Synthesis wrapper — OrangeCrab r0.2 (ECP5-25F)
│ ├── ck37_orangecrab.lpf Pin constraints (LED/UART)
│ └── ck37_orangecrab_unconstrained.lpf Timing-only variant
├── sim/
│ └── nav_tb.v Navigation kernel testbench — 25/25 passing
├── asm/
│ ├── ck37asm.py Assembler — octal, Q1.25, full 26-bit encoding
│ └── gen_labels.py Regenerates nav/nav_labels.vh from kernel
├── nav/
│ ├── nav_kernel.asm Navigation kernel (198 words, CK37 assembly)
│ ├── nav_kernel.hex Assembled ROM image ($readmemh format)
│ ├── nav_kernel.lst Listing with addresses and encoding
│ └── nav_labels.vh Auto-generated handler addresses (Verilog include)
├── docs/
│ ├── ISA_v2.md Full ISA specification with manual corrections
│ ├── confirmed_architecture.md
│ └── instruction_encoding.md
├── Makefile sim / labels / synth / pnr / bit / flash
├── README.md
└── RUNBOOK_NO_HARDWARE.md

Quick Start

Simulate (25/25 tests)

# Requires iverilog
sudo apt install iverilog
make sim
# Assembles nav_kernel.asm → nav_kernel.hex, then runs nav_tb.v# Expected: ╔══╗ RESULTS: 25 passed, 0 failed ╚══╝

Synthesise (Yosys → ECP5)

# Requires: yosys, nextpnr-ecp5, fpga-trellis, dfu-util
sudo apt install yosys nextpnr-ecp5 fpga-trellis dfu-util
make synth # → build/ck37.json
make pnr # → build/ck37_routed.config
make bit # → build/ck37.bit
make flash # DFU flash to OrangeCrab r0.2

See RUNBOOK_NO_HARDWARE.md for step-by-step instructions with expected output at each stage.

Assemble manually

python3 asm/ck37asm.py nav/nav_kernel.asm --memh -o nav/nav_kernel.hex
python3 asm/gen_labels.py # regenerates nav/nav_labels.vh

Synthesis Results (ECP5-25F, OrangeCrab r0.2)

Target: LFE5U-25F-8MG285C (OrangeCrab r0.2)
Tool: Yosys 0.52 (ABC9) + nextpnr-ecp5 0.6
Resource utilisation:
LUT4: 1,978 / 24,288 ( 8%)
TRELLIS_FF: 386 / 24,288 ( 1%)
DP16KD: 12 / 12 (100% — exactly fits ECP5-25F)
CCU2C: 264 (carry chains)
Timing (post-route, speed grade 8):
ck37_clk max: 85.46 MHz PASS at 10.00 MHz (8.5× margin)
clk_48m max: 435.54 MHz PASS at 48.00 MHz
7 warnings, 0 errors
Clock divider: 48 MHz ÷ 17 ≈ 2.82 MHz (target: 2.860 MHz)
Note: integer divider gives 98.7% of target frequency.
A fractional PLL can hit 2.860 MHz exactly for production.

The BRAM fit is exact — 8192 × 26-bit data memory maps to exactly 12 × 18Kbit EBR blocks. Parity checking is active in simulation (ifndef SYNTHESIS) and stubbed to zero on silicon to free the 13th block.


What's Left Before You Flash

1. Flash via DFU

# Hold BTN0 while plugging USB to enter DFU bootloader
sudo apt install dfu-util
make flash

2. Verify boot on hardware

On power-up the CPU boots at PM_BASE (0x1000), loads gain constants, runs self-test, then enters the IRQ-driven nav loop:

  • led_g (green) heartbeats at ~1 Hz — CPU is running
  • led_r (red) stays off — not halted
  • led_b (blue) stays off — no parity errors

3. UART debug transmitter (optional)

uart_tx is currently held high (idle). Implement a 57600 8N1 transmitter in syn/ck37_syn_top.v to stream the AR register value each IRQ4 cycle.

4. Wire up ADC/DAC SPI

Connect ADS8688A (ADC) and DAC8568 (DAC) to the GPIO pins and restore the LPF constraints. The AIO module (rtl/ck37_aio.v) is already written; it just needs the SPI physical wiring.


CPU Bug History

All bugs found and fixed across the development cycle:

#ModuleBug
1asm.ORG 0100000 overflow → corrected to 010000
2asmFirst-pass PC not incremented for .FLOAT/.WORD → all ROM constants resolved to same address
3asmShort-form (halvord) encoding placed bits in wrong positions → disabled, always full 26-bit
4cpuGOTOPR not detected — opcodes embedded in IR[25:23], masked by casez fall-through
5cpuSC+ halvord: value placed in AR[12:0] instead of AR[25:13]
6cpuS= halvord: symmetric placement error
7cpuAND/ANDOP/OR/OROP: operated on AR[12:0] instead of AR[25:13]
8cpuABSOP: subtracted from lower half instead of upper half
9cpuC+OP/+OP/-OP/S+/S-/SIGNOP: same upper/lower swap
10cpuMUL: treated AR as unsigned — negative AR gave wrong product
11cpuINT_EN reset to 0 — interrupts never fired
12cpuINT_EN cleared in S_INTR — interrupts fired once then stopped
13kernelSELF_TEST and SAVE_BOOT at same address (000055) — INDGOTO jumped to PC=0
14kernelSPD_TARGET never loaded from ROM at boot
15kernelONE_HALF never loaded from ROM at boot
16kernelAU_THR init used SC+ before S=SC+ overwrote AR
17kernelERR_HDG/ERR_ALT only computed in IRQ5 — IRQ4 used stale values
18rtl/dioUnpacked array ports not synthesisable by Yosys → flattened to packed vectors
19rtl/dioFor-loop reset with variable index on packed vector → replaced with direct zero assign
20rtl/diobi01_shadow double sequential assignment → merged into single concatenation
21rtl/dioDouble-slice bu_data[N:M][P:Q] → replaced with flat computed slice
22rtl/memParity logic not guarded → 13 EBR needed vs 12 available; guarded with `ifndef SYNTHESIS
23synAsync set+reset FFs (initial values + async reset) → removed initialisers, reset-only blocks

Navigation Kernel

The nav kernel (nav/nav_kernel.asm, 198 words at PM_BASE=0x1000) implements a full PID navigation loop:

IRQ4 handler (2.864ms fast loop):

  • Reads sensors: PITCH, ROLL, YAW, AIRSPEED, BARO, BEARING
  • Computes heading error (ERR_HDG) and altitude error (ERR_ALT) fresh every cycle
  • Calls ALT_CONTROL, HDG_CONTROL, SPEED_CONTROL via GOTOPR
  • Writes actuator commands: CMD_AIL, CMD_ELEV, CMD_RUD, CMD_THR

IRQ5 handler (34.37ms slow loop):

  • Reads GPS velocity (VEL_N, VEL_E, VEL_D)
  • Integrates position: POS_N, POS_E, POS_ALT += VEL × DT_SLOW

Handler addresses (current assembly):

LabelAddress (hex)Octal
BOOT0x1000010000
IRQ4_HANDLER0x102F010057
IRQ5_HANDLER0x104D010115
ALT_CONTROL0x1069010151
HDG_CONTROL0x1079010171
SPEED_CONTROL0x1089010211

Primary Sources

  1. FMV "Beskrivning CK37, Del 1" (1985-11-01, M7773-460011) — Official Swedish Air Force maintenance manual, Saab-Scania — Confirms: word length, number format, instruction encoding, memory map, interrupt vectors, I/O architecture, clock timings

  2. Bengt Jiewertz, "Central Computer for aircraft Saab 37, Viggen" — Datasaab Vänner paper, written by the CK37's chief designer — Appendices 2 & 3: prototype specifications, instruction timing, I/O counts — Available: datasaab.se/Papers/Articles/Viggenck37.pdf

  3. "BITS & BYTES — TEMA FLYG, ur Datasaabs historia" (1995, ISBN 91-972464-17) — Datasaabs Vänner, edited by Bengt Jiewertz — Chapters by original design team members

  4. DCS World AJS37 Viggen — CK37 Input Codes cheatsheet (community document) — Reveals the pilot data-entry interface: 6-digit BCD keypad codes, mode structure, ~700 system variables across 30 program blocks


The Drone

The CK37 was designed to replace a human navigator in a single-seat aircraft. Its entire function was sensor fusion, dead-reckoning navigation, and weapon delivery computation — which maps directly onto autonomous drone flight:

Viggen systemDrone equivalent
INS platform (attitude)BNO085 IMU
Air data (IAS, altitude)Pitot + baro
Radio altimeterLidar/radar altimeter
Attack radar (range)GPS range to waypoint
HUD outputTelemetry downlink
Weapon releasePayload trigger
Pilot data panelGCS command uplink

Contributing

This project is part of Former Lab — a sovereignty-focused hardware and software lab building across embedded systems, RF, and autonomous platforms.

The immediate priorities are:

  • Hardware bring-up — OrangeCrab flash, UART debug tap
  • ADC/DAC wiring — connect ADS8688A + DAC8568 to the AIO module
  • Del 3 schematics — the CEM circuit schematic volumes (Flik 4–5) for board-accurate replica
  • Kanaldata pages — sida 35–40 for electrical I/O specifications

If you have access to CK37 programming documentation or Del 3 schematics, please open an issue.


Licence


Former Lab — Sweden

About

A soft-core FPGA replica of the Saab CK37 — the world's first IC-based airborne computer, rebuilt from the original 1963 FMV maintenance manual and running a PID navigation loop in the original Q1.25 assembly. Target: OrangeCrab r0.2 (ECP5-25F)

Resources

Stars

12 stars

Watchers

1 watching

Forks

Contributors

Languages