/m68k-fpga-soc

M68000-compatible SOC for Lattice iCE40 FPGA using j68 CPU core

Primary LanguageVerilogOtherNOASSERTION

M68000-compatible SOC for iCE40 FPGA

License: ISC FPGA: iCE40HX8K CPU: j68

A complete Motorola 68000-compatible System-on-Chip implementation for Lattice iCE40 FPGAs, featuring the j68 CPU core with external SRAM, LED control, and comprehensive ModelSim verification.


Table of Contents


Features

CPU Core (j68)

  • Motorola 68000-compatible instruction set
  • Microcode-based architecture - not cycle-accurate but functionally equivalent
  • Stack-based with Forth-like microcode
  • All M68000 instructions implemented
  • Auto-vector interrupts supported
  • 3× frequency overhead - requires ~3× higher clock than real MC68000

Memory System

  • 4 KB Boot ROM @ 0x00000000 (on-chip BRAM)
  • 512 KB External SRAM @ 0x00001000 (via unified controller)
  • 16-bit data bus for efficient memory access
  • Single-cycle BRAM reads for boot ROM
  • 4-cycle SRAM accesses (controlled by unified SRAM controller)

Peripherals

  • 2× GPIO LEDs @ 0xFF000000 (memory-mapped)
  • Debug UART register @ 0xFF000004 (simulation only)
  • Extensible I/O space at 0xFF000000+ (1,392 LCs / 12 BRAMs available)

Verification

  • Complete ModelSim test suite (PicoRV32-style)
  • LED toggle pattern verification (10 cycles, 40 state changes)
  • Icarus Verilog support for open-source simulation
  • Waveform dumps (VCD format)
  • Automated test scripts with progress monitoring

Architecture

┌─────────────────────────────────────────────────────────────┐
│                  M68000 SOC Top Level                       │
│                   (m68k_soc_top.v)                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────────┐      ┌────────────────┐                 │
│  │   j68 CPU    │◄────►│  Boot ROM      │                 │
│  │  (M68000)    │      │  (4 KB BRAM)   │                 │
│  │              │      └────────────────┘                 │
│  │  - 32-bit    │                                          │
│  │  - Microcode │      ┌────────────────┐                 │
│  │  - 20-bit µOP│◄────►│ SRAM Controller│◄───► SRAM      │
│  │  - 2KB µROM  │      │   (Unified)    │      (512KB)    │
│  │  - 256B Dec  │      └────────────────┘                 │
│  └──────────────┘                                          │
│         ▲                                                  │
│         │                                                  │
│         ▼                                                  │
│  ┌──────────────┐                                          │
│  │ Peripherals  │                                          │
│  ├──────────────┤                                          │
│  │ LED Control  │ @ 0xFF000000                            │
│  │ Debug UART   │ @ 0xFF000004                            │
│  └──────────────┘                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

j68 CPU Core Details

The j68 is a microcode-based reimplementation of the Motorola 68000:

  • Not cycle-accurate - functional compatibility prioritized
  • ~3-120 microcode cycles per instruction (average ~20)
  • 2048×20-bit microcode ROM (5× 2048×4-bit BRAMs)
  • 256×36-bit decode ROM (1× BRAM)
  • Stack-based execution with internal stacks for data/instructions
  • Forth-like microcode for compact implementation

Resource Utilization

Lattice iCE40HX8K-CT256

Resource Used Available Utilization
Logic Cells (LCs) 6,288 7,680 81.9%
Block RAMs 20 32 62.5%
PLBs 786 960 81.9%
I/O Pins ~40 256 ~15.6%

Resource Breakdown

CPU Core (j68):

  • Logic Cells: ~5,500 LCs (estimated)
  • Block RAMs: 18 BRAMs
    • 5× BRAMs for microcode (2048×20-bit split into 5× 4-bit)
    • 1× BRAM for decode ROM (256×36-bit)
    • 12× BRAMs for internal stacks and registers

SOC Infrastructure:

  • Logic Cells: ~788 LCs
    • SRAM Controller: ~400 LCs
    • Boot ROM: 1 BRAM (4KB)
    • LED/Peripheral logic: ~100 LCs
    • Clock/Reset: ~50 LCs

Available for Expansion:

  • 1,392 Logic Cells (18.1% of device)
  • 12 Block RAMs (37.5% of device)
  • Sufficient for: UART, SPI, Timers, DMA, Interrupt Controller

Performance

Clock Frequencies

Clock Target Status Measured Timing Margin
25 MHz (design target) ✓ PASS 46.53 MHz +21.53 MHz
40 MHz (typical) ✓ PASS 46.53 MHz +6.53 MHz
47.93 MHz (max) ✓ PASS 47.93 MHz 0 MHz

Recommended operating frequency: 25-40 MHz

Effective M68000 Performance

Due to the ~3× microcode frequency overhead:

FPGA Clock Equivalent M68K Speed Notes
25 MHz ~8.3 MHz Conservative, guaranteed timing
40 MHz ~13.3 MHz Typical operation, good margin
47 MHz ~15.7 MHz Maximum, tight timing

Comparison to original MC68000:

  • Original MC68000: 8 MHz (1979), 16 MHz (1982)
  • This implementation @ 40 MHz ≈ 13.3 MHz MC68000

Instruction Performance

Instruction Type Microcode Cycles Notes
Register operations 6-12 cycles MOV, ADD, SUB, etc.
Memory access 15-30 cycles Load/Store with addressing
Branches 8-15 cycles Conditional/unconditional
Complex instructions 40-120 cycles DIVU, MULU, shifts

Average CPI (Cycles Per Instruction): ~20 microcode cycles

Timing Critical Path

Critical path: 20.86 ns (47.93 MHz)
  Logic delay:  5.10 ns (24%)
  Routing delay: 15.77 ns (76%)

Bottleneck: Memory interface routing (CPU ↔ SRAM controller)

Optimization opportunities:

  • Register CPU-SRAM interface (+5-10 MHz potential)
  • Reduce fanout on memory bus (+2-5 MHz potential)
  • Pipeline memory controller (+10-15 MHz potential)

Hardware Requirements

Supported FPGA Boards

Tested Configuration

  • Lattice iCE40HX8K-CT256 evaluation board
  • 512 KB SRAM (16-bit data bus, 18-bit address)
  • 50 MHz oscillator (on-board)
  • 2× LEDs for status indication

Minimum Requirements

  • iCE40HX4K or larger (7,680+ LCs, 32+ BRAMs)
  • 256 KB+ SRAM (16-bit or 8-bit bus)
  • 25 MHz+ clock source
  • JTAG programmer (or SPI flash programmer)

Pin Assignments

See ice40hx8k_ct256.pcf for complete pin configuration.

Critical Signals:

CLK:        H16  (50 MHz oscillator)
SRAM_ADDR:  A3-D3, A2-D2 (18-bit address bus)
SRAM_DATA:  A1-D1 (16-bit bidirectional data bus)
SRAM_CS_N:  E1   (Chip select, active low)
SRAM_OE_N:  F1   (Output enable, active low)
SRAM_WE_N:  G1   (Write enable, active low)
LED1:       P12  (GPIO output)
LED2:       P11  (GPIO output)

Software Requirements

FPGA Build Tools

Required:

  • Yosys (>= 0.9) - Verilog synthesis
  • nextpnr-ice40 (>= 0.2) - Place & Route
  • icepack - Bitstream packing
  • icetime - Timing analysis

Installation (Ubuntu/Debian):

# Option 1: oss-cad-suite (recommended)
wget https://github.com/YosysHQ/oss-cad-suite-build/releases/download/latest/oss-cad-suite-linux-x64-latest.tgz
tar -xzf oss-cad-suite-linux-x64-latest.tgz
export PATH="$(pwd)/oss-cad-suite/bin:$PATH"

# Option 2: Distribution packages
sudo apt install fpga-icestorm yosys nextpnr-ice40

M68K Toolchain

Required:

  • m68k-elf-gcc - Cross-compiler
  • m68k-elf-as - Assembler
  • m68k-elf-ld - Linker
  • m68k-elf-objcopy - Binary utilities
  • m68k-elf-objdump - Disassembler

Installation:

# Option 1: marsdev toolchain (recommended)
git clone https://github.com/andwn/marsdev.git
cd marsdev && make && cd ..
export PATH="$(pwd)/marsdev/m68k-elf/bin:$PATH"

# Option 2: Build from source (GNU)
# See: https://github.com/m68k-elf-gcc

Simulation Tools (Optional)

ModelSim (commercial):

# Intel ModelSim-Intel FPGA Edition
# Download from: https://www.intel.com/content/www/us/en/software/programmable/quartus-prime/modelsim.html
export PATH="/path/to/modelsim_ase/bin:$PATH"

Icarus Verilog (open-source):

sudo apt install iverilog gtkwave

Quick Start

1. Clone Repository

git clone https://github.com/yourusername/m68k-fpga-soc.git
cd m68k-fpga-soc

2. Build Bitstream

make clean
make build

# Output: build/m68k_soc.bin

3. Program FPGA

# Using iceprog (direct FTDI programmer)
sudo iceprog build/m68k_soc.bin

# Using OpenOCD (JTAG)
openocd -f interface/ftdi/olimex-arm-usb-ocd-h.cfg \
        -f target/ice40.cfg \
        -c "init; svf build/m68k_soc.svf; exit"

4. Verify Operation

# LEDs should toggle in pattern:
# LED1 → LED2 → BOTH → OFF (repeating)

Building the SOC

Build Targets

# Full build (synthesis + P&R + bitstream)
make build

# Individual stages
make synth        # Synthesis only
make pnr          # Place & Route only
make pack         # Bitstream generation only
make timing       # Timing analysis only

# Cleanup
make clean        # Remove build artifacts
make distclean    # Remove all generated files

Build Output

build/
├── m68k_soc.bin          # FPGA bitstream (program this!)
├── m68k_soc.json         # Synthesis output (Yosys)
├── m68k_soc.asc          # Place & route output (nextpnr)
├── synth.log             # Synthesis log
├── pnr.log               # Place & route log
└── timing.rpt            # Timing analysis report

Build Options

Edit Makefile to customize:

# Clock frequency target (MHz)
FREQ = 25

# FPGA device
DEVICE = hx8k

# Package
PACKAGE = ct256

# Synthesis options
SYNTH_OPTS = -dsp  # Enable DSP blocks (not used in this design)

Simulation

ModelSim Simulation (Recommended)

Full test with monitoring:

cd sim
./run_test_sim_long.sh

# Expected output:
# ✓✓✓ TEST PASSED ✓✓✓
# All 10 LED pattern cycles completed successfully!

Interactive simulation:

cd sim
vsim -c -do "do compile_test_sim.do; do run_test_sim.do"

# View waveforms:
vsim -view m68k_test_sim.vcd

Icarus Verilog Simulation

Quick test:

cd sim
./run_test_iverilog.sh

# Output: test_sim_run.log, m68k_test_sim.vcd

View waveforms:

gtkwave m68k_test_sim.vcd

Simulation Test Firmware

The test firmware (firmware/test_sim.S) performs:

  1. Prints "Sim Startup\r\n" to debug UART
  2. Toggles LEDs in pattern: LED1 → LED2 → BOTH → OFF
  3. Repeats for 10 cycles (40 LED state changes)
  4. Prints "Test Complete\r\n"
  5. Halts with STOP instruction

Expected simulation time: ~965 µs @ 50 MHz Pattern cycle time: ~59 µs per cycle


Firmware Development

Building Firmware

cd firmware
make clean
make

# Output: test_sim.hex (installed to ../sim/)

Memory Layout

0x00000000:  Exception vectors (8 bytes)
  0x00000000:  Initial SSP (Stack Pointer)
  0x00000004:  Initial PC (Program Counter = _start)

0x00000008:  Boot code (.text section)
  - LED toggle routines
  - Delay loops
  - Debug output functions

0x00001000:  RAM (.data section)
  - String constants
  - Variables

0x00004000:  Stack (grows down from here)
  - 16 KB initial stack space

Linker Script

The linker script (m68k.ld) defines:

  • ROM: 4 KB @ 0x00000000 (code + vectors)
  • RAM: 508 KB @ 0x00001000 (data + bss + heap + stack)
  • Stack: 512 KB - 16 KB = 0x0007C000 (top of RAM)

M68000 Assembly Example

| M68000 Exception Vector Table
.section .vectors, "ax"
.long   0x00080000      | Initial SSP (top of SRAM @ 512KB)
.long   _start          | Initial PC (reset vector)

.text
.globl _start

_start:
    | Initialize stack pointer
    lea     0x00004000, %sp

    | Write to LED register
    move.w  #0x01, 0xFF000000    | LED1 ON, LED2 OFF

    | Simple delay loop
    moveq   #10, %d0
delay:
    subq.l  #1, %d0
    bne     delay

    | Infinite loop
halt:
    stop    #0x2700
    bra     halt

Disassembly and Analysis

# Generate disassembly
make

# View disassembly
cat test_sim.lst

# Check symbol table
m68k-elf-nm test_sim.elf

# Verify memory layout
m68k-elf-objdump -h test_sim.elf

Memory Map

Address Space Layout

0x00000000 - 0x00000FFF : Boot ROM (4 KB, BRAM, read-only)
    Vector table, boot code, constants

0x00001000 - 0x0007FFFF : External SRAM (508 KB, read-write)
    RAM data, BSS, heap, stack

0xFF000000 - 0xFF0000FF : Peripheral I/O (256 bytes)
    0xFF000000: LED Control Register (16-bit)
      Bit 0: LED1 (0=OFF, 1=ON)
      Bit 1: LED2 (0=OFF, 1=ON)
      Bits 2-15: Reserved

    0xFF000004: Debug UART Register (8-bit, simulation only)
      Write: Send character to stdout
      Read: Always returns 0x00

    0xFF000008+: Reserved for future peripherals

Memory Access Timing

Region Cycles Notes
Boot ROM 1 Single-cycle BRAM access
SRAM 4 Via unified SRAM controller
Peripherals 1 Direct register access

Project Structure

m68k-fpga-soc/
├── README.md              # This file
├── LICENSE                # ISC License
├── Makefile               # Top-level build system
│
├── hdl/                   # Hardware Description (Verilog)
│   ├── m68k_soc_top.v     # Top-level SOC integration
│   ├── m68k_boot_rom.v    # Boot ROM with initialization
│   ├── sram_controller_unified.v  # External SRAM controller
│   └── j68_cpu/           # j68 M68000 CPU core (upstream)
│       ├── cpu_j68.v      # CPU top-level
│       ├── j68_*.v        # CPU submodules
│       └── *.mem, *.mif   # Microcode ROM initialization
│
├── firmware/              # M68000 Firmware
│   ├── test_sim.S         # Original assembly test
│   ├── m68k.ld            # Original linker script
│   ├── Makefile           # Original build system
│   └── examples/          # Firmware examples
│       ├── 01_asm_simple/ # Assembly LED blink
│       └── 02_c_blink/    # C LED blink with crt0
│
├── sim/                   # Simulation Environment
│   ├── m68k_test_sim_tb.v # ModelSim testbench
│   ├── sram_model_16bit.v # SRAM behavioral model
│   ├── compile_test_sim.do    # ModelSim compile script
│   ├── run_test_sim.do        # ModelSim run script
│   ├── run_test_sim_long.sh   # Long-running test monitor
│   ├── run_test_iverilog.sh   # Icarus Verilog test script
│   └── convert_mif_to_hex.sh  # MIF to HEX converter
│
├── build/                 # Build outputs (generated)
│   ├── m68k_soc.bin       # FPGA bitstream
│   ├── m68k_soc.json      # Synthesis netlist
│   ├── m68k_soc.asc       # Place & route output
│   └── *.log, *.rpt       # Build logs and reports
│
└── docs/                  # Documentation
    ├── TEST_REPORT.md     # ModelSim verification report
    └── PERFORMANCE_ANALYSIS.md  # Performance documentation

Verification

ModelSim Verification Suite

Test Coverage:

  • ✓ CPU reset sequence (8192 cycles)
  • ✓ Boot ROM execution
  • ✓ SRAM read/write operations
  • ✓ LED register writes (41 writes verified)
  • ✓ LED pattern sequencing (40 state changes)
  • ✓ Pattern cycle completion (10/10 cycles)
  • ✓ Memory controller state machine
  • ✓ Clock domain stability

Test Results:

✓✓✓ TEST PASSED ✓✓✓

Execution Time: 964.99 µs
LED Pattern Cycles: 10/10 (100%)
LED State Changes: 40
CPU Activity:
  - Data Reads: 1,473
  - Data Writes: 45
  - LED Writes: 41

Test Reproduction

cd sim
./run_test_sim_long.sh

# Monitor progress:
tail -f /tmp/m68k_test_sim.log

# Verify success:
grep "TEST PASSED" /tmp/m68k_test_sim.log

Waveform Analysis

Critical signals to observe:

  • clk_50mhz - System clock
  • rst_n - Reset (active low)
  • cpu_address[31:0] - CPU address bus
  • cpu_rd_data[15:0] - CPU read data
  • cpu_wr_data[15:0] - CPU write data
  • led1, led2 - LED outputs
  • sram_addr[17:0] - SRAM address
  • sram_data[15:0] - SRAM data (bidirectional)

Known Issues

Minor Issues (Non-blocking)

1. Instruction Fetch Counter Always Zero

  • Status: Testbench detection issue
  • Impact: None (CPU verified working via LED toggling)
  • Cause: j68 microcode may not assert FC=010 for instruction fetches
  • Workaround: Use data read/write counts instead

2. No Debug UART Output in Simulation

  • Status: $write/$fflush mechanism issue
  • Impact: None (not critical for LED toggle test)
  • Expected: "Sim Startup\r\n" message
  • Workaround: LED pattern verification sufficient

Future Enhancements

  • Add real UART peripheral (16550-compatible)
  • Implement SPI master for SD card interface
  • Add timer/counter peripherals
  • Implement interrupt controller
  • Add DMA controller for memory transfers
  • Pipeline memory controller for higher frequency
  • Support 8-bit SRAM devices
  • Add Wishbone bus interface
  • Implement hardware breakpoint support

Contributing

Contributions are welcome! Please follow these guidelines:

Reporting Issues

  • Use GitHub Issues
  • Include synthesis/simulation logs
  • Provide FPGA board details
  • Specify toolchain versions

Pull Requests

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for new functionality
  4. Ensure builds pass (make clean build)
  5. Run simulation tests (cd sim && ./run_test_sim_long.sh)
  6. Update documentation (README.md, comments)
  7. Commit with clear messages
  8. Push to branch (git push origin feature/amazing-feature)
  9. Open Pull Request

Coding Standards

  • Verilog: Follow IEEE 1364-2001 standard
  • Comments: Document all module interfaces
  • Naming: snake_case for signals, CamelCase for modules
  • Indentation: 4 spaces (no tabs)
  • License: Add ISC license header to new files

License

SOC Integration

Copyright (c) 2025 Michael Wolak

This project (SOC integration and supporting infrastructure) is licensed under the ISC License.

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

SPDX-License-Identifier: ISC

Third-Party Components

j68 CPU Core Copyright (c) 2011-2018 Frederic Requin The j68 core is included under its original license terms. See hdl/j68_cpu/ directory for complete license information.


Acknowledgments

Credits

  • Frederic Requin - j68 M68000-compatible CPU core (GitHub)
  • Motorola/Freescale/NXP - Original MC68000 architecture and documentation
  • Lattice Semiconductor - iCE40 FPGA family and development tools
  • Yosys/nextpnr teams - Open-source FPGA synthesis and PnR tools

References

M68000 Documentation:

j68 CPU Core:

FPGA Tools:

M68K Resources:


Contact

Michael Wolak Email: mikewolak@gmail.com

Project Link: https://github.com/yourusername/m68k-fpga-soc


Project Status

Current Status: ✓ Verified in ModelSim simulation Hardware Testing: Pending (synthesis successful, timing closed) Next Milestone: Physical FPGA board testing

Last Updated: November 2025