Cómo seleccionar la línea a un demux 1:4 en verliog desde un procesador de software NIOS II

Soy nuevo en verilog. Estoy usando este demux 1:4 como se describe en esta página web (código suministrado).

1: 4 código verilog demultiplexor

Mi pregunta es en relación con la línea de selección. Tengo un procesador de software NIOS II en la fpga con una aplicación escrita en c ejecutándose en él. ¿Cómo controlaría la línea de selección desde el NIOS? Supongo que escribiría un valor en alguna ubicación, pero no estoy seguro de cómo funcionaría con precisión.

Apreciar y consejos de sugerencias.

Respuestas (1)

Para que NIOS acceda a los periféricos en la FPGA, debe realizar un proceso llamado "Asignación de memoria". Esencialmente, esto se reduce a construir una estructura para asignar el periférico a una dirección en el mapa de memoria NIOS para que pueda acceder a él.

El procesador NIOS utiliza un maestro de datos Avalon-MM para acceder a todos los periféricos, por lo que para conectar las líneas de control de su demultiplexor, debe envolverlas en una interfaz esclava Avalon-MM que luego se conecta al maestro de datos y se le asigna un DIRECCIÓN.

La forma más sencilla de realizar la conexión es utilizar un controlador PIO Avalon-MM, que es básicamente un núcleo IP que se puede utilizar para conectar entradas o salidas al bus Avalon-MM. Esto se usa con frecuencia para asignar pines de E/S externos a NIOS, pero también se puede usar para conexiones internas.

Alternativamente, puede crear directamente una interfaz Avalon-MM en su código demultiplexor. Puede encontrar las especificaciones de la interfaz aquí , que le indicarán qué hace cada una de las señales. Para ayudarlo, puede usar la siguiente plantilla de Verilog que creé y uso en todos los núcleos de IP que hago para usar con NIOS.

module avalon_mm_template_hw (
    //Clock and Reset inputs
    input             clock,
    input             reset,

    //CSR Interface
    input      [ 1:0] csr_address,
    input             csr_write,
    input      [31:0] csr_writedata,
    input             csr_read,
    output reg [31:0] csr_readdata,
    input      [ 3:0] csr_byteenable,

    //Interrupt Interface
    output            csr_irq
);

//
// CSR Interface
//

localparam IRQS = 2; //Number of interrupt sources
reg  [         IRQS-1:0] irqEnable;
wire [         IRQS-1:0] irqSources;
reg  [         IRQS-1:0] irqEdgeDetect;
reg  [         IRQS-1:0] irqAsserted;

assign csr_irq    = |(irqAsserted & irqEnable);  //IRQ line goes high when any unmasked IRQ line is asserted.
assign irqSources = { "<irqSourceName>", "<anotherIrqSourceName>" }; //IRQ sources - IRQ will be triggered at rising edge.

wire [31:0] dataFromMaster;
wire [31:0] dataToMaster [3:0];
wire [31:0] bitenable;

//Convert byte enable signal into bit enable (basically each group of 8 bits is assigned to the value of the corresponding byte enable.
assign bitenable = {{8{csr_byteenable[3]}},{8{csr_byteenable[2]}},{8{csr_byteenable[1]}},{8{csr_byteenable[0]}}}; 
assign dataFromMaster = csr_writedata & bitenable;

//Set up the Read Data Map for the CSR.
//                       |31                           24|23  16|15  8|7  0|
assign dataToMaster[0] = {                                  "<signalName>" }; //Input signals are mapped to correct bits
assign dataToMaster[1] = {                                  "<signalName>" }; //at the correct addresses here.
assign dataToMaster[2] = {                                  "<signalName>" };
assign dataToMaster[3] = { {(8 - IRQS){1'b0}} irqAsserted,           24'b0 };

always @ (posedge clock) begin
    if (csr_read) begin
        csr_readdata <= dataToMaster[csr_address]; //when CSR read is asserted, clock the correct address of the CSR map on to the outputs.
    end
end

//Generate the IRQ edge detection logic.
genvar i;
generate for (i = 0; i < IRQS; i=i+1) begin : irq_loop
    always @ (posedge clock or posedge reset) begin
        if (reset) begin
            irqAsserted[i]   <= 1'b0;
            irqEdgeDetect[i] <= 1'b0;
        end else begin
            if (csr_write && (csr_address == 2'd3) && dataFromMaster[i+24]) begin 
                //writing a 1 to the corresponding bit in address 3 clears IRQ flag.
                irqAsserted[i] <= 1'b0;
            end else if (irqSources[i] & ~irqEdgeDetect[i]) begin //At rising edge of IRQ Source, assert its flag.
                irqAsserted[i] <= 1'b1;
            end
            irqEdgeDetect[i] <= irqSources[i];
        end
    end
end endgenerate

//CSR Write logic
always @ (posedge clock or posedge reset) begin
    if (reset) begin
        irqEnable       <= {(IRQS){1'b0}};
        "<signalName>"  <= {("<signalWidth>"){1'b0}};
    end else if (csr_write) begin //When a write is issued, update the registers at the corresponding address.
        if (csr_address == 2'd0) begin
            "<signalName>" <= ("<signalName>" & ~bitenable[0+:"<signalWidth>"]) | dataFromMaster[0+:"<signalWidth>"];
        end
        if (csr_address == 2'd3) begin
            //Doesn't have to be at this address, just an example
            irqEnable   <= (  irqEnable & ~bitenable[8+:IRQS]) | dataFromMaster[8+:IRQS]; //IRQ enable mask
        end
        //And so on for all write addresses
    end
end



//... End CSR ...


endmodule

Esa plantilla maneja habilitaciones de bytes, lectura y escritura, y también interrupciones. Puede eliminar cosas como controladores de interrupción para algo tan simple como un demux.

Si está utilizando esto con Qsys, deberá crear un contenedor TCL para su núcleo de IP. No mostraré una plantilla contenedora completa, pero a continuación se muestra cómo agregaría la interfaz Avalon-MM y, opcionalmente, la interfaz IRQ. Muestro esto porque hay muchas propiedades diferentes para las interfaces Avalon-MM, y las que se muestran a continuación coinciden con la plantilla anterior y se sabe que funcionan.

# 
# connection point csr
# 
add_interface csr avalon end
set_interface_property csr addressUnits WORDS
set_interface_property csr associatedClock clock
set_interface_property csr associatedReset reset
set_interface_property csr bitsPerSymbol 8
set_interface_property csr burstOnBurstBoundariesOnly false
set_interface_property csr burstcountUnits WORDS
set_interface_property csr explicitAddressSpan 0
set_interface_property csr holdTime 0
set_interface_property csr linewrapBursts false
set_interface_property csr maximumPendingReadTransactions 0
set_interface_property csr maximumPendingWriteTransactions 0
set_interface_property csr readLatency 1
set_interface_property csr readWaitStates 0
set_interface_property csr readWaitTime 0
set_interface_property csr setupTime 0
set_interface_property csr timingUnits Cycles
set_interface_property csr writeWaitTime 0
set_interface_property csr ENABLED true

add_interface_port csr csr_address address Input 2
add_interface_port csr csr_readdata readdata Output 32
add_interface_port csr csr_writedata writedata Input 32
add_interface_port csr csr_write write Input 1
add_interface_port csr csr_read read Input 1
add_interface_port csr csr_byteenable byteenable Input 4
set_interface_assignment csr embeddedsw.configuration.isFlash 0
set_interface_assignment csr embeddedsw.configuration.isMemoryDevice 0
set_interface_assignment csr embeddedsw.configuration.isNonVolatileStorage 0
set_interface_assignment csr embeddedsw.configuration.isPrintableDevice 0

# 
# connection point csr_irq
# 

add_interface csr_irq interrupt sender
set_interface_property csr_irq associatedAddressablePoint csr
set_interface_property csr_irq associatedClock clock
set_interface_property csr_irq associatedReset reset
set_interface_property csr_irq irqScheme NONE

add_interface_port csr_irq csr_irq irq Output 1
Hola @Tom Carpenter, muchas gracias por tu detallada y útil respuesta. Intentaré poner en práctica tu sugerencia.