El diseño simula perfectamente pero no funcionará en FPGA

Primero, gracias por la ayuda de ayer. Esta vez documentaré mi código correctamente.

Por lo tanto, se nos encargó crear un parquímetro que necesitara 4 entradas, una que suma 50 segundos, otra que suma 150 segundos, otra que suma 250 segundos y otra que suma 500 segundos. Cuando quedan más de 10 segundos, un led verde debe parpadear con un período de 2 segundos. Cuando quedan menos de 10 segundos, un led rojo debe parpadear con un período de 2 segundos, y cuando no quedan segundos, un led rojo debe parpadear con un período de 1 segundo. Se supone que cada ciclo de reloj sin entrada resta uno del medidor.

Tuvimos la tarea de usar un antirrebote, así como una máquina de estado de un solo pulso para las entradas y una pantalla de 7 segmentos para las salidas. Por lo tanto, utilicé una máquina de estado para mi suma y el parpadeo del LED, luego envié el contador a un convertidor binario a BCD y luego a una pantalla de BCD a 7 segmentos. Me pregunto si estropeé el reloj y de alguna manera la simulación ignora mis errores, haciendo que el FPGA no pueda usar correctamente mi código.

sin más preámbulos, aquí están mis fragmentos de código:

Módulo superior

module parkingmeter(clk,rst,b0,b1,b2,b3,out0,out1,out2,out3,GRNLED,REDLED);
    input b0,b1,b2,b3,clk,rst;
    output [6:0] out0,out1,out2,out3;
    output GRNLED,REDLED;
    wire outt0,outt1,outt2,outt3;
    wire [15:0] counter;
    wire [3:0] bcd0,bcd1,bcd2,bcd3;
    wire clkout;
    clockdivider onesec(clk,clkout);
    add_sub yep(b0,clkout,rst,outt0);
    add_sub yesh(b1,clkout,rst,outt1);
    add_sub yeah(b2,clkout,rst,outt2);
    add_sub ok(b3,clk,rst,outt3);
    controlparker Second(outt0,outt1,outt2,outt3,clkout,rst,counter,REDLED,GRNLED);
    EC Third(counter,bcd0,bcd1,bcd2,bcd3,out0,out1,out2,out3);
endmodule

mi modulo de rebote

module cleandebounce(clk,rst,I0,out);
    input clk,rst,I0;
    output out;
    reg f0,f1;
    always @ (posedge clk, posedge rst) begin
       if (rst==1) begin
            f0 <= I0;
            f1 <= f0;
        end else begin
            f0 <= 0;
            f1 <= 0;
       end
    end
    assign out = f1;
endmodule

Mi máquina de estado de un solo pulso

module add_sub(in,clk,rst,out);
    input in,clk,rst;
    output reg out = 1'b0;
    reg state = 1'b0;
    wire outt;
    cleandebounce one(clk,rst,in,outt);
    always @ (posedge clk,posedge rst) begin
        case(state)
            1'b0: begin
                if (rst==1) begin
                    out <= 0;
                    if (outt == 1) begin
                        out <= 1'b1;
                        state <= 1'b1;
                    end else state <= 1'b0;
                end else begin
                    out <= 1'b0;
                    state <= 1'b0;
                end
            end
            1'b1: begin
                out <= 1'b0;
                if (outt == 1) begin
                    out <= 1'b0;
                    state <= 1'b1;
                end else state <= 1'b0;
            end
        endcase
    end
endmodule

Y mi módulo para agregar las entradas, así como para encender y apagar los leds.

module controlparker(B0,B1,B2,B3,clk,rst,counter,REDLED,GRNLED);
    input B0,B1,B2,B3,clk,rst;
    output reg [15:0] counter = 16'b0000000000000000;
    reg state = 1'b0;
    reg [2:0] area = 3'b000;
    output reg REDLED = 0;
    output reg GRNLED = 0;
    always @ (posedge clk, posedge rst) begin
        case(state)
            0: begin
                if (rst==1) begin
                    if (counter > 0)
                        counter <= counter - 1;
                    if (counter > 9999)begin
                        counter <= 9999;
                    end
                    state <= 1;
                end else begin
                    counter <= 0;
                    state <= 0;
                end
            end
            1: begin
                if (B0 == 1) begin
                    counter <= counter + 16'b00000000000110010;
                    state <= 0;
                end else if (B1 == 1) begin
                    counter <= counter + 16'b00000000010010110;
                    state <= 0;
                end else if (B2 == 1) begin
                    counter <= counter + 16'b00000000011111010;
                    state <= 0;
                end else if (B3 == 1) begin
                    counter <= counter + 16'b00000000111110010;
                    state <= 0;
                end else state <= 0;
            end
        endcase
    end        
    always @ (posedge clk, posedge rst) begin
        case(area)
            3'b000: begin
                if (rst==1)begin
                    if (counter >= 10)begin
                        GRNLED <= 1;
                        REDLED <= 0;
                        area <= 3'b001;
                    end
                    else if (counter < 10 && counter > 0) begin
                        REDLED <= 1;
                        GRNLED <= 0;
                        area <= 3'b010;
                    end
                    else REDLED <= ~REDLED;
                end
                else begin
                    REDLED <= 0;
                    GRNLED <= 0;
                end
            end
            3'b001: begin
                GRNLED <= 0;
                area <= 3'b000;
            end
            3'b010: begin
                REDLED <= 0;
                area <= 3'b000;
            end
        endcase
    end
endmodule

Mi módulo convierte BinarytoBCD, así como la salida de pantalla de 7 segmentos:

module EC(in,bcd0,bcd1,bcd2,bcd3,out0,out1,out2,out3);
    input [15:0] in;
    output reg [3:0] bcd0 = 4'b0000;
    output reg [3:0] bcd1 = 4'b0000;
    output reg [3:0] bcd2 = 4'b0000;
    output reg [3:0] bcd3 = 4'b0000;
    output reg [6:0] out0 = 7'b0000000;
    output reg [6:0] out1 = 7'b0000000;
    output reg [6:0] out2 = 7'b0000000;
    output reg [6:0] out3 = 7'b0000000;
    reg [15:0] temp;
    integer i;
    always @ (in) begin
        bcd0 = 4'b0000;
        bcd1 = 4'b0000;
        bcd2 = 4'b0000;
        bcd3 = 4'b0000;
        temp = in;
        for(i=15; i>=0; i=i-1) begin
            if (bcd3 >= 4'b0101)
                bcd3 = bcd3 + 4'b0011;
            if (bcd2 >= 4'b0101)
                bcd2 = bcd2 + 4'b0011;
            if (bcd1 >= 4'b0101)
                bcd1 = bcd1 + 4'b0011;
            if (bcd0 >= 4'b0101)
                bcd0 = bcd0 + 4'b0011;
            bcd3 = bcd3 << 1;
            bcd3[0] = bcd2[3];
            bcd2 = bcd2 << 1;
            bcd2[0] = bcd1[3];
            bcd1 = bcd1 << 1;
            bcd1[0] = bcd0[3];
            bcd0 = bcd0 << 1;
            bcd0[0] = temp[i];
        end
    end
    always @ (bcd0) begin
        if (bcd0==4'b0000) out0 = 7'b0000001;
        else if (bcd0==4'b0001) out0 = 7'b1001111;
        else if (bcd0==4'b0010) out0 = 7'b0010010;
        else if (bcd0==4'b0011) out0 = 7'b0000110;
        else if (bcd0==4'b0100) out0 = 7'b1001100;
        else if (bcd0==4'b0101) out0 = 7'b0100100;
        else if (bcd0==4'b0110) out0 = 7'b0100000;
        else if (bcd0==4'b0111) out0 = 7'b0001111;
        else if (bcd0==4'b1000) out0 = 7'b0000000;
        else if (bcd0==4'b1001) out0 = 7'b0000100;
        else out0=7'b0000001;
    end
    always @ (bcd1) begin
        if (bcd1==4'b0000) out1 = 7'b0000001;
        else if (bcd1==4'b0001) out1 = 7'b1001111;
        else if (bcd1==4'b0010) out1 = 7'b0010010;
        else if (bcd1==4'b0011) out1 = 7'b0000110;
        else if (bcd1==4'b0100) out1 = 7'b1001100;
        else if (bcd1==4'b0101) out1 = 7'b0100100;
        else if (bcd1==4'b0110) out1 = 7'b0100000;
        else if (bcd1==4'b0111) out1 = 7'b0001111;
        else if (bcd1==4'b1000) out1 = 7'b0000000;
        else if (bcd1==4'b1001) out1 = 7'b0000100;
        else out1=7'b0000001;
    end
    always @ (bcd2) begin
        if (bcd2==4'b0000) out2 = 7'b0000001;
        else if (bcd2==4'b0001) out2 = 7'b1001111;
        else if (bcd2==4'b0010) out2 = 7'b0010010;
        else if (bcd2==4'b0011) out2 = 7'b0000110;
        else if (bcd2==4'b0100) out2 = 7'b1001100;
        else if (bcd2==4'b0101) out2 = 7'b0100100;
        else if (bcd2==4'b0110) out2 = 7'b0100000;
        else if (bcd2==4'b0111) out2 = 7'b0001111;
        else if (bcd2==4'b1000) out2 = 7'b0000000;
        else if (bcd2==4'b1001) out2 = 7'b0000100;
        else out2=7'b0000001;
    end
    always @ (bcd3) begin
        if (bcd3==4'b0000) out3 = 7'b0000001;
        else if (bcd3==4'b0001) out3 = 7'b1001111;
        else if (bcd3==4'b0010) out3 = 7'b0010010;
        else if (bcd3==4'b0011) out3 = 7'b0000110;
        else if (bcd3==4'b0100) out3 = 7'b1001100;
        else if (bcd3==4'b0101) out3 = 7'b0100100;
        else if (bcd3==4'b0110) out3 = 7'b0100000;
        else if (bcd3==4'b0111) out3 = 7'b0001111;
        else if (bcd3==4'b1000) out3 = 7'b0000000;
        else if (bcd3==4'b1001) out3 = 7'b0000100;
        else out3=7'b0000001;
    end
endmodule

Y, por último, mi divisor de reloj lo alimente a cada módulo que requiere un reloj para funcionar correctamente en FPGA:

module clockdivider(clk,clkout);
    input clk;
    output clkout;
    reg [24:0] q = 0;
    always @ (posedge clk) begin
        q <= q + 1;
    end
    assign clkout = q[0];
endmodule

Así que ahí está todo. Cuando habilito mi FPGA, muestra números aleatorios aunque no haya presionado ningún botón. ¿Cómo es esto posible? Soy relativamente nuevo en verilog, así que si hay alguna forma de simplificar mi código, lo agradecería mucho. De nuevo, todo simula a la perfección. Gracias a todos

A esto le falta toda la información crítica sobre cómo se crea una instancia y se conecta en el FPGA: ¡ni siquiera menciona la parte o la herramienta de síntesis! Además, no debe dividir un reloj en código HDL, use un generador de reloj o divida para crear una habilitación de reloj .
Verifique su archivo de configuración de hardware, sus valores iniciales y ¿ha sincronizado sus entradas externas con su dominio de reloj? Muchas cosas pueden suceder en simulación que no coinciden con sythensis.
Mi maestro nunca ha repasado nada de lo que ustedes están diciendo. Todo lo que he hecho es asignar puertos FPGA a los respectivos pines de entrada y salida. Ella nos dio el código divisor del reloj. Nuestra placa es una Altera DE 2 si eso ayuda en algo
Sí, no te enseñan todo lo que necesitas saber para hacer que las cosas funcionen en un FPGA real.
¿Intentó ejecutar la simulación en un diseño posterior a la ubicación y posterior al enrutamiento?
El maestro nunca ha mencionado el diseño posubicado o posdireccionado
@helpneeded Así que pregúntele a su maestro acerca de los diseños "post-colocados" y "post-enrutados" y cuáles tienen beneficios cuando...
Mi consejo: agregue demoras artificialmente pequeñas para CADA asignación "sin bloqueo" (como contador <= # 0.1 contador - 1;) consulte electronics.stackexchange.com/a/365262/117785 Es posible que encuentre un cambio drástico en el comportamiento de su Verilog modelo en comparación con su modelo ideal.
Bueno, para empezar, ese divisor de reloj solo divide el reloj de entrada por dos. No estoy seguro de lo que pretende hacer, pero probablemente tendría sentido elegir un bit de salida diferente al bit 0.
Sí, mis disculpas, configuré el reloj así para fines de simulación. Originalmente se configuró en el bit 24, con una frecuencia de alrededor de 1,5 hZ.
Si su FPGA comienza mostrando números aleatorios, entonces parece que no ha resuelto el reinicio del encendido del hardware, y que su código de simulación lo está haciendo por usted como una cortesía automática.

Respuestas (1)

Podría haber muchos problemas ya que parece no estar familiarizado con los FPGA reales, así que los enumeraré a medida que avanzamos:

  1. ¿Están todas las entradas externas sincronizadas con el dominio de reloj de su FPGA? Las señales que ingresan pueden hacer una transición en medio de los bordes del reloj FPGA, lo que conduce a la metaestabilidad. La forma de lidiar con esto es pasar la entrada externa a través de una cadena de flip-flops antes de usarla (es decir, copiar la entrada a través de la cadena de señales/registros de cada reloj). Cada vez que se pasa, las posibilidades de que una señal metaestable llegue a su núcleo funcional se vuelven menos probables hasta que es muy pequeña. El mínimo son dos, los equipos de alta confiabilidad pueden usar tres. Esto debería ser obvio, pero lo diré de todos modos: este tiene que ser el PRIMER paso de cualquier señal que ingrese al FPGA. Si desea eliminar el rebote o filtrar la señal (como en el n. ° 2), debe hacerlo DESPUÉS de este paso, ya que la metaestabilidad no permitirá que nada más funcione correctamente.

  2. ¿Tus botones externos tienen rebote? Cuando los contactos electromecánicos chocan entre sí, no se acoplarán limpiamente y se conectarán y desconectarán repetidamente hasta que las cosas se estabilicen. La electrónica es lo suficientemente rápida para captar esto. Puede filtrar las entradas de varias maneras en un FPGA. Algunos enfoques son: (a) Una vez que se detecta una transición, ignorar todas las transiciones posteriores durante un período de tiempo (llamado supresión) (b) Solo pasar el estado de entrada para que lo usen otros valores si se ha estabilizado para una cierta cantidad de muestras .

  3. Su FPGA necesita una forma de saber qué señales están asociadas con qué pines. También necesita decirle al FPGA qué tipo de pines deben ser. La forma en que se hace esto depende de su software de síntesis. Esto debe ser correcto.

  4. Su FPGA también necesita saber cuál será la velocidad del reloj para saber cuánto tiempo puede permitir que una señal se propague, ya que todas las señales (especialmente las señales de reloj) deben llegar a sus destinos a tiempo para que el circuito funcione correctamente.

  5. Las señales de reloj deben ir a todas partes en un FPGA y deben llegar a todas partes aproximadamente al mismo tiempo. No enruta los relojes a través de la estructura FPGA normal, ya que es demasiado variable y demasiado lento para ejecutar los relojes a través de toda la lógica configurable de FPGA. El sesgo del reloj será demasiado alto. Los FPGA tienen redes de reloj dedicadas para distribuir el reloj en todo el chip con un retraso de propagación mínimo. Debe utilizarlos si desea distribuir un reloj.

Las palabras clave como "posege" y "negedge" son muy especiales y le dicen al software que se trata de una señal de reloj, por lo que se enruta a través de la red de distribución de reloj dedicada. Esto ocurrirá automáticamente con cada señal asociada con estas palabras clave, pero solo hay unos pocos números de estas en un FPGA. Por lo tanto, no use esta palabra clave para cosas que no sean señales de reloj reales. Si desea ver un flanco ascendente en una señal que no sea de reloj, escriba un módulo separado que compare el estado lógico anterior con el actual para ver si es diferente.

  1. Del mismo modo, no divida los relojes en la estructura FPGA por la misma razón. No pase el reloj por la lógica configurable. Utilice el bloque de hardware divisor de reloj en la FPGA o utilice señales de habilitación de reloj en sus módulos.

Una señal de habilitación de reloj es una señal que solo sube durante un solo pulso de reloj antes de volver a bajar. Se activa cuando un módulo hará algo pero el módulo no está desconectado. El módulo todavía está cronometrado fuera del reloj FPGA principal (a través de la red de distribución de reloj). Puede crear un módulo que esté sincronizado con el reloj de la FPGA pero emita una activación de reloj cada N ciclos y use esto para activar la activación de eventos en otros módulos. Todos los módulos todavía tienen el reloj de la FPGA y el hecho de que la habilitación del reloj expire después de un ciclo de reloj garantiza que los módulos no activen continuamente cada ciclo de reloj cuando no se supone que lo hagan.

  1. Los flip flops en el FPGA también tienen hardware de reinicio para que pueda tener reinicios asíncronos (ya que la lógica configurable en el tejido FPGA odia lo asíncrono). Una señal colocada en la lista de sensibilidad pero que NO tiene una palabra clave como "posege" o "negedge" se interpretará como un reinicio de hardware. NO use "posege" o "negedge" con una señal de reinicio.

Regla de lista de sensibilidad en HDL