fpga verilog dual access

0

Necesito escribir en un registro de 2 fuentes .. en este caso, un host pci y un microcontrolador. El 2 nunca accederá al registro al mismo tiempo (básicamente, una vez que se realiza el PCI, lo entrega al otro host, que tendrá acceso exclusivo hasta que finalice).

Dado que los dominios de reloj son diferentes, no puedo tener múltiples procesos de escritura en el mismo registro ..

always @(posedge pciclk or negedge nrst)
   if pci_wr & pci_addr == 0
        cntl_reg = pci_data

always @(posedge mcclk or negedge nrst)
   if mc_wr & mc_addr == 0
        cntl_reg = mc_data

Entonces, ¿cómo se hace esto típicamente? No estoy seguro si esta es una pregunta de arquitectura fundamental, o simplemente una pregunta de sintaxis sobre cómo escribir la lista de sensibilidad.

    
pregunta Ben Nguyen

1 respuesta

2

El registro FPGA práctico (un conjunto de flip-flops D) solo tiene un pin de reloj por lo que sirve exactamente un dominio de reloj. Tenga en cuenta este hardware de bajo nivel al escribir el código HDL.

Cuando una señal cruza de un dominio de reloj a otro, es común usar una tubería de tres registros, con la primera etapa en el dominio de reloj de origen y el segundo y tercer registros en el dominio de reloj de destino. Esto causa una latencia predecible, pero evita las condiciones de carrera y el comportamiento indefinido.

// From Xilinx ISE 14.1 Language Templates
// Verilog | Synthesis Constructs | Coding Examples | Misc | Asynchronous Input Synchronization
module async_input_sync(
    input clk,
    (* TIG="TRUE", IOB="FALSE" *) input async_in,
    output reg sync_out
    );
(* ASYNC_REG="TRUE", SHREG_EXTRACT="NO", HBLKNM="sync_reg" *) reg [1:0] sreg;
always @(posedge clk) begin
    sync_out <= sreg[1];
    sreg <= {sreg[0], async_in};
end
endmodule

Sincronice pci_data, pci_wr y pci_addr en el dominio de reloj mcclk. Por ejemplo:

wire [xxx] pci_mc_data; // pci_ signal in pciclk clock domain, source mc_data
wire pci_mc_wr; // pci_ signal in pciclk clock domain, source mc_data
wire [xxx] pci_mc_addr; // pci_ signal in pciclk clock domain, source mc_data
async_input_sync(pciclk, mc_data[xxx], pci_mc_data[xx]);
async_input_sync(pciclk, mc_wr, pci_mc_wr);
async_input_sync(pciclk, mc_addr[xxx], pci_mc_addr[xx]);

Sincronice mc_data, mc_wr y mc_addr en el dominio de reloj pciclk. Por ejemplo:

wire [xxx] mc_pci_data; // mc_ signal in mcclk clock domain, source pci_data
async_input_sync(mcclk, pci_data[xxx], mc_pci_data[xx]);

Tendrá un registro en el dominio del reloj pciclk, y otro registro en el dominio del reloj mcclk. Ambos registros tienen los mismos datos después de que la señal se propaga a través del dominio del reloj. Por ejemplo, el registro en el lado pci podría verse así:

// All of these signals are in the pciclk clock domain
always @(posedge pciclk) begin
    if (pci_wr & pci_addr == 0) begin
        pci_cntl_reg <= pci_data;
    end
    if (pci_mc_wr & pci_mc_addr == 0) begin
        pci_cntl_reg <= pci_mc_data;
    end
end

También tenga en cuenta el uso de la asignación no bloqueante < = para ayudar a la herramienta de síntesis a reconocer que está solicitando un conjunto de D flip flops. La palabra clave verilog register es solo un tipo de datos, no siempre resulta en la síntesis de un flip-flop D.

    
respondido por el MarkU

Lea otras preguntas en las etiquetas