Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Porting to the Nexys 4 DDR

Motivation

The base HaDes-V system targets the Digilent Basys 3 board, built around the Xilinx Artix-7 XC7A35T FPGA. While sufficient for the educational microcontroller lab, this platform is fundamentally inadequate for running DOOM:

ResourceBasys 3 (XC7A35T)Nexys 4 DDR (XC7A100T)
Logic Cells33,280101,440
BRAM225 KB486 KB
DSP Slices90240
External MemoryNone128 MB DDR2 SDRAM

The most critical limitation is the lack of external memory. DOOM’s WAD file alone is just over 4 MB, far exceeding the BRAM available. The Nexys 4 DDR’s 128 MB DDR2 SDRAM provides more than enough capacity for the game’s code, WAD data, framebuffers, and runtime state. The larger FPGA also provides the logic headroom needed for caches, additional peripherals, and the M-Extension.

Changes

Constraints File (synth/nexys4ddr.xdc)

A new constraint file maps all the top-level ports to the Nexys 4 DDR’s physical pins:

  • Clock: 100 MHz primary oscillator at pin E3, configured with a create_clock constraint at 10 ns period.
  • MMCM placement: The MMCM is locked to location MMCME2_ADV_X1Y1 and the input clock is set with CLOCK_DEDICATED_ROUTE FALSE to avoid routing restrictions.
  • Switches: 16 switches mapped to bank 14/15/34/35 pins.
  • LEDs: 16 LEDs mapped to bank 14/15 pins.
  • 7-Segment Display: 8 segments and 4 anode selects mapped.
  • Buttons: 5 buttons (center, up, left, right, down).
  • VGA: 4-bit R/G/B channels, H-sync, V-sync.
  • UART: RX/TX on the USB-RS232 interface.
  • SD Card (SPI): CS, SCLK, MOSI, MISO, and reset on the micro SD connector.
  • PS/2: Clock and data pins with pull-up enabled.
  • Audio PWM: PWM output and audio shutdown on the audio amplifier header.
  • DDR2: Full physical interface pins (DQ, DQS, address, bank, control, clock, etc.).

The XDC file header notes that the port is “very lackluster”; some switch, button, and display pins are not correctly mapped because the focus was on getting DOOM operational rather than full board coverage.

Synthesis Script (synth/synth.tcl)

The synthesis script was adapted from the Basys 3 version:

Dynamic board selection:

if {[info exists env(TARGET_BOARD)]} {
    set TARGET_BOARD $env(TARGET_BOARD)
} elseif {[llength $argv] > 0} {
    set TARGET_BOARD [lindex $argv 0]
} else {
    set TARGET_BOARD "basys3"
}

Part and constraints selection:

if {$TARGET_BOARD == "nexys4ddr"} {
    set FPGA_PART "xc7a100tcsg324-1"
    set CONSTRAINTS_FILE "$ROOT/synth/nexys4ddr.xdc"
} else {
    set FPGA_PART "xc7a35tcpg236-1"
    set CONSTRAINTS_FILE "$ROOT/synth/basys3.xdc"
}

MIG IP integration: For the Nexys target, the script locates the DDR2 MIG IP (.xci), reads it, generates all targets, and synthesizes the IP:

if {$TARGET_BOARD == "nexys4ddr"} {
    set MIG_XCI "$ROOT/ip/ddr2_mig/mig_7series_0.xci"
    if {[file exists $MIG_XCI]} {
        read_ip $MIG_XCI
        generate_target all [get_ips mig_7series_0]
        synth_ip [get_ips mig_7series_0]
    }
}

Enhanced optimization directives: The original Basys 3 flow (synth_design + basic opt_design + place_design + route_design) was replaced with a much more aggressive flow to meet timing at 75 MHz:

synth_design -top top -part $FPGA_PART -retiming
opt_design -directive Explore
place_design -directive ExtraNetDelay_high
phys_opt_design -directive AggressiveExplore
route_design -directive Explore
phys_opt_design -directive AggressiveFanoutOpt

Top Module (synth/top.sv)

The top module was expanded to accommodate the Nexys 4 DDR’s richer peripheral set and the new DDR2 memory subsystem:

Ports: increased from the original 4-bit switches/LEDs to 16-bit vectors, added 7-segment display, audio PWM, PS/2 keyboard, and DDR2 physical interface signals.

Clock generation: the system uses a two-stage clocking architecture:

  1. MMCME2_BASE generates the CPU and memory clocks from the 100 MHz input:

    • 200 MHz for the MIG DDR2 controller
    • 75 MHz for the CPU core (the operating frequency)
  2. PLLE2_BASE × 2 generate the VGA pixel clock:

    • First PLL multiplies to 106 MHz (100 MHz / 5 × 53 / 10)
    • Second PLL divides to 25.175 MHz (106 MHz / 2 × 19 / 40)

The CPU runs on ui_clk — the clock output from the MIG’s user interface — eliminating a clock domain crossing between the CPU and the DDR2 controller.

DDR2 integration: the DDR2 MIG IP is instantiated with its native application interface (app_addr, app_cmd, app_rd_data, etc.). A custom wishbone_128_ddr2_bridge translates between the 128-bit Wishbone bus and the MIG’s native interface. The bridge is connected to the system’s Wishbone memory arbiter.

Build System (Makefile)

The Makefile gained a BOARD parameter, defaulting to basys3:

BOARD ?= basys3

synthesis: $(BUILD_DIR)/$(C_DIR)/bootloader/init.mem
    cd $(BUILD_DIR)/$(SYNTH_DIR) && $(VIVADO) -mode $(MODE) \
        -source $(CURDIR)/$(SYNTH_DIR)/synth.tcl -tclargs $(BOARD)

This allows building for either board:

make synthesis BOARD=nexys4ddr   # Build for Nexys 4 DDR
make synthesis                    # Build for Basys 3 (default)

Summary

The port to the Nexys 4 DDR involved creating board-specific constraints, adapting the synthesis infrastructure for dual-board support, integrating the DDR2 MIG IP, and redesigning the top-level module to support all required peripherals. The dynamic board selection mechanism allows the same repository to target both the original Basys 3 and the Nexys 4 DDR, which proved useful during development and testing.