Skip to content

Latest commit

 

History

History
593 lines (469 loc) · 12.8 KB

File metadata and controls

593 lines (469 loc) · 12.8 KB

Troubleshooting Guide

Problemlösungen für FPGA-Entwicklung

🎯 Übersicht

Dieser Guide hilft bei der systematischen Fehlersuche in FPGA-Projekten, von einfachen Syntax-Fehlern bis zu komplexen Timing-Problemen.


Hardware-Probleme

ULX3S Board Issues

Problem: Board wird nicht erkannt

# Diagnose
openFPGALoader --detect
lsusb | grep Future
dmesg | tail -20

# Lösungsansätze
sudo usermod -a -G dialout $USER    # User zu dialout-Gruppe
sudo udevadm control --reload-rules  # udev rules neu laden
# Neustart erforderlich nach Gruppenänderung

# USB-Permissions prüfen
ls -la /dev/ttyUSB* /dev/ttyACM*

# Alternative JTAG-Verbindung
openFPGALoader --cable ft232 --detect

Problem: Inkonsistente Stromversorgung

Symptome: Sporadische Resets, instabile Operation
Diagnose mit Multimeter:
- 3.3V Rail: 3.135V - 3.465V (±5%)
- 2.5V Rail: 2.375V - 2.625V (±5%)  
- 1.1V Rail: 1.045V - 1.155V (±5%)

Lösungen:
- USB-Kabel wechseln (Spannungsabfall)
- USB-Hub mit externer Stromversorgung
- Externes 5V Netzteil verwenden

Problem: FPGA startet nicht nach Programming

// Debug-Checkliste:
// 1. Clock-Signal vorhanden?
assign debug_led[0] = clk;

// 2. Reset-Logic korrekt?
reg [15:0] reset_counter;
always @(posedge clk) begin
    if (reset_counter < 16'hFFFF)
        reset_counter <= reset_counter + 1;
end
assign debug_led[1] = reset_counter[15]; // Shows reset completion

// 3. PLL locked?
assign debug_led[2] = pll_locked;

Toolchain-Probleme

Yosys Synthesis Issues

Problem: "Unknown module" Fehler

# Fehler-Beispiel:
ERROR: Module `my_module' not found!

# Debugging:
yosys -p "read_verilog src/*.v; hierarchy -check -top top_module"

# Lösungen:
1. Alle .v Files in yosys command einschließen
2. Module-Namen überprüfen (case-sensitive)
3. File-Pfade verifizieren

Problem: Synthesis-Warnungen verstehen

Warning: Wire is used but has no driver
→ Unconnected input, assign default value

Warning: Wire has multiple drivers  
→ Bus contention, use tri-state logic

Warning: Found latch for signal
→ Incomplete case/if statement, add default

nextpnr Place & Route Issues

Problem: Timing Constraints nicht erfüllt

# Timing-Report analysieren:
nextpnr-ecp5 --85k --package CABGA381 --json design.json \
    --lpf constraints.lpf --report timing_report.txt

# Critical Path Analysis:
grep -A 20 "Critical path report" timing_report.txt

# Lösungsansätze:
1. Clock-Frequenz reduzieren
2. Pipeline-Stufen hinzufügen  
3. Logic-Optimierung (weniger LUT-Ebenen)
4. Register-Balancing

Problem: Routing-Konflikte

ERROR: Failed to route net 'signal_name'

Lösungen:
1. Design vereinfachen (weniger Logik)
2. Pin-Assignments prüfen  
3. Floorplanning constraints
4. Alternative FPGA-Pinout

HDL Code Issues

Verilog Common Mistakes

Problem: Inferred Latches

// FALSCH - erzeugt Latch:
always @(*) begin
    if (condition)
        output = input_a;
    // Fehlt: else clause!
end

// RICHTIG:
always @(*) begin
    if (condition)
        output = input_a;
    else
        output = input_b; // oder default value
end

Problem: Clock Domain Crossing

// GEFÄHRLICH - Metastability:
reg signal_crossed;
always @(posedge clk_domain2) begin
    signal_crossed <= signal_from_domain1; // Direkte Verwendung!
end

// SICHER - Synchronizer:
reg [2:0] sync_reg;
always @(posedge clk_domain2) begin
    sync_reg <= {sync_reg[1:0], signal_from_domain1};
end
assign signal_crossed = sync_reg[2];

Problem: Blocking vs Non-blocking Assignments

// FALSCH in sequential logic:
always @(posedge clk) begin
    a = b;      // Blocking assignment
    c = a;      // Uses NEW value of a (combinational)
end

// RICHTIG für sequential logic:
always @(posedge clk) begin
    a <= b;     // Non-blocking  
    c <= a;     // Uses OLD value of a (register chain)
end

// RICHTIG für combinational logic:
always @(*) begin
    temp = a & b;       // Blocking OK
    output = temp | c;  // Uses NEW value of temp
end

Simulation Issues

Problem: Simulation vs. Hardware unterschiedlich

// Häufige Ursachen:

1. Uninitialized Registers:
// Simulation: reg defaults to 'x'
// Hardware: reg can power up to any value
reg [7:0] counter = 8'h00; // Explicit initialization

2. Race Conditions:
// Simulation ist deterministisch
// Hardware kann unterschiedliche Delays haben

3. Clock Domain Issues:
// Setup/Hold Violations in Hardware
// Simulation sieht ideale Timing

Problem: Waveform-Analyse

// Bessere Debug-Signale:
module debug_wrapper(
    input clk,
    input reset,
    input [7:0] data_in,
    output [7:0] data_out
);

// Original design
my_design dut(.*);

// Debug-Ausgaben für Simulation
always @(posedge clk) begin
    if (debug_enable) begin
        $display("Time=%0t: data_in=%h, data_out=%h, internal_state=%h", 
                 $time, data_in, data_out, dut.internal_signal);
    end
end

// VCD Dump mit mehr Details
initial begin
    $dumpfile("detailed_debug.vcd");
    $dumpvars(0, debug_wrapper);      // Alle Signale
    $dumpvars(1, dut.internal_module); // Interne Module
end

endmodule

Debugging-Strategien

Systematische Fehlersuche

1. Divide and Conquer

// Große Designs in Teile zerlegen:

// Stufe 1: Minimaler Test
module minimal_test(
    input clk,
    output [7:0] led
);
    reg [23:0] counter;
    always @(posedge clk) counter <= counter + 1;
    assign led = counter[23:16];
endmodule

// Stufe 2: Ein Modul hinzufügen
module add_one_module(
    input clk,
    output [7:0] led
);
    minimal_test base(.clk(clk), .led(led[3:0]));
    // Neues Modul testen
    new_module test(.clk(clk), .out(led[7:4]));
endmodule

2. Signal Tracing

// Interne Signale nach außen routen:
module debug_signals(
    input clk,
    input [7:0] data_in,
    output [7:0] data_out,
    
    // Debug-Ausgänge
    output [7:0] debug_state,
    output debug_valid,
    output debug_error
);

// Hauptlogik
main_logic ml(
    .clk(clk),
    .data_in(data_in),
    .data_out(data_out),
    // Interne Signale exportieren
    .internal_state(debug_state),
    .valid_flag(debug_valid),
    .error_flag(debug_error)
);

endmodule

3. Built-in Self-Test (BIST)

module bist_wrapper(
    input clk,
    input test_mode,
    input [7:0] normal_input,
    output [7:0] normal_output,
    output test_pass
);

// Test-Pattern Generator
reg [7:0] test_patterns [0:15];
reg [3:0] test_index;
reg [7:0] expected_results [0:15];

initial begin
    test_patterns[0] = 8'h00;   expected_results[0] = 8'h00;
    test_patterns[1] = 8'hFF;   expected_results[1] = 8'hFF;
    test_patterns[2] = 8'h55;   expected_results[2] = 8'hAA;
    // ... weitere Test-Vektoren
end

// DUT with muxed inputs
wire [7:0] dut_input = test_mode ? test_patterns[test_index] : normal_input;
wire [7:0] dut_output;

design_under_test dut(
    .clk(clk),
    .input(dut_input), 
    .output(dut_output)
);

// Test-Logik
reg test_running;
reg all_tests_pass;

always @(posedge clk) begin
    if (test_mode && !test_running) begin
        test_running <= 1;
        test_index <= 0;
        all_tests_pass <= 1;
    end else if (test_running) begin
        if (dut_output != expected_results[test_index]) begin
            all_tests_pass <= 0;
        end
        
        if (test_index == 15) begin
            test_running <= 0;
        end else begin
            test_index <= test_index + 1;
        end
    end
end

assign normal_output = test_mode ? 8'h00 : dut_output;
assign test_pass = all_tests_pass;

endmodule

Performance-Probleme

Timing-Optimierung

Critical Path Analysis

// Lange kombinatorische Pfade vermeiden:

// SCHLECHT - langer kombinatorischer Pfad:
always @(*) begin
    result = ((((a + b) * c) - d) >> 2) & mask;
end

// BESSER - Pipeline mit Registern:
always @(posedge clk) begin
    stage1 <= a + b;
    stage2 <= stage1 * c;  
    stage3 <= stage2 - d;
    stage4 <= stage3 >> 2;
    result <= stage4 & mask;
end

Resource Utilization

# Resource-Report analysieren:
yosys -p "synth_ecp5 -top design; stat" design.v

# Ausgabe verstehen:
Number of cells:
  TRELLIS_FF      150    # Flip-Flops (Register)
  TRELLIS_LUT4    75     # 4-Input LUTs
  TRELLIS_CARRY   8      # Carry-Chain Elemente

# Optimierung:
1. Unused logic eliminieren
2. Resource-sharing (gemeinsame Ressourcen)
3. Pipeline-Balancing

Spezielle FPGA-Probleme

Clock-Domain Issues

Problem: Setup/Hold Violations

// Timing-Constraints definieren:
// In .lpf file:
FREQUENCY PORT "clk" 25 MHZ;
MAXDELAY FROM CELL "input_reg*" TO CELL "output_reg*" 35 ns;

// Multi-Cycle Paths:
MULTICYCLE FROM CELL "slow_logic*" TO CELL "result_reg*" 2;

// False Paths (asynchrone Signale):
FALSEPATH FROM CELL "async_input*" TO CELL "*";

Problem: Clock Skew

// Clock-Distribution verbessern:

// SCHLECHT - manueller Clock-Tree:
wire clk_div2 = clk_counter[0];
wire clk_div4 = clk_counter[1];

// BESSER - dedizierte Clock-Resources:
EHXPLLL pll_inst(
    .CLKI(clk_input),
    .CLKOP(clk_main),     // Primary clock
    .CLKOS(clk_div2),     // Secondary clock  
    .CLKOS2(clk_div4),    // Tertiary clock
    .LOCK(pll_locked)
);

Memory Interface Problems

Problem: BRAM Inference

// Korrekte BRAM-Inferenz:

// Funktioniert - synchroner Read:
always @(posedge clk) begin
    if (we)
        ram[addr] <= data_in;
    data_out <= ram[addr];    // Registered output
end

// Funktioniert NICHT - asynchroner Read:
assign data_out = ram[addr]; // Inferiert Distributed RAM

// Dual-Port korrekt:
always @(posedge clk_a) begin
    if (we_a) ram[addr_a] <= data_in_a;
    data_out_a <= ram[addr_a];
end

always @(posedge clk_b) begin
    data_out_b <= ram[addr_b];  // Read-only port
end

Testing und Verification

Testbench Best Practices

Comprehensive Testing

module comprehensive_testbench;
    // Clock and Reset
    reg clk = 0;
    reg reset = 1;
    
    always #5 clk = ~clk;  // 100 MHz
    
    initial begin
        #100 reset = 0;
    end
    
    // DUT instantiation
    wire [7:0] dut_output;
    reg [7:0] dut_input;
    
    design_under_test dut(.*);
    
    // Test vectors
    reg [15:0] test_vectors [0:1023];
    integer test_count;
    
    initial begin
        $readmemh("test_vectors.hex", test_vectors);
        test_count = 0;
    end
    
    // Directed tests
    initial begin
        wait(!reset);
        
        // Test 1: Basic functionality
        test_basic_operation();
        
        // Test 2: Edge cases
        test_edge_cases();
        
        // Test 3: Random inputs
        test_random_inputs();
        
        // Test 4: Stress test
        test_stress_conditions();
        
        $display("All tests completed!");
        $finish;
    end
    
    // Test tasks
    task test_basic_operation;
        begin
            dut_input = 8'h00;
            #20;
            assert(dut_output == 8'h00) else $error("Basic test failed");
            
            dut_input = 8'hFF;
            #20;
            assert(dut_output == 8'hFF) else $error("Basic test failed");
        end
    endtask
    
    task test_edge_cases;
        begin
            // Test overflow, underflow, etc.
            dut_input = 8'hFE;
            #20;
            // Check expected behavior
        end
    endtask
    
    // Coverage monitoring
    reg [7:0] input_coverage [0:255];
    
    always @(posedge clk) begin
        if (!reset) begin
            input_coverage[dut_input] <= 1;
        end
    end
    
    // Check coverage at end
    final begin
        integer i, covered = 0;
        for (i = 0; i < 256; i = i + 1) begin
            if (input_coverage[i]) covered = covered + 1;
        end
        $display("Input coverage: %d/256 (%d%%)", covered, covered*100/256);
    end
    
endmodule

Quick Reference

Häufige Fehlermeldungen

"Cannot assign to wire in procedural block"
→ Verwenden Sie 'reg' statt 'wire' für procedural assignments

"Multiple drivers for wire"  
→ Bus contention - verwenden Sie tri-state logic

"Signal is used but never assigned"
→ Unconnected input - assign default value

"Timing constraint not met"
→ Reduce clock frequency oder add pipeline stages

"Unsupported or unknown PLI function"
→ Simulation-only code in synthesis - use `ifdef SIMULATION

Debug-Checkliste

  • Clock-Signal vorhanden und stabil?
  • Reset-Logic korrekt (active high/low)?
  • Pin-Assignments in constraints file?
  • Alle Module-Instanzen verbunden?
  • Clock-Domain-Crossings synchronisiert?
  • Timing-Constraints definiert?
  • Resource-Utilization im Rahmen?
  • Testbench validiert das Design?

Dieser Guide wird kontinuierlich erweitert basierend auf häufigen Problemen und Community-Feedback.