Para que NIOS pueda acceder a los periféricos de la FPGA, es necesario realizar un proceso llamado "Memory Mapping". Esencialmente, esto se reduce a construir el tejido para mapear el periférico a una dirección en el mapa de memoria de 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 tu demultiplexor, necesitas envolverlas en una interfaz esclava Avalon-MM que luego se conecta al maestro de datos y se le asigna una dirección.
La forma más sencilla de realizar la conexión es utilizar un controlador PIO de Avalon-MM, que es básicamente un núcleo IP que puede utilizarse para conectar entradas o salidas al bus de Avalon-MM. Esto se usa frecuentemente para mapear pines IO externos a NIOS, pero también puede usarse para conexiones internas.
Como alternativa, puede crear directamente una interfaz Avalon-MM en su código demultiplexor. Puede encontrar el especificaciones de la interfaz aquí que le dirá lo que hace cada una de las señales. Para ayudarte, puedes utilizar la siguiente plantilla de Verilog que he creado y utilizo en todos los núcleos 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 la habilitación de bytes, la lectura y la escritura, y también las interrupciones. Puedes eliminar cosas como los manejadores de interrupción para algo tan simple como un demux.
Si estás usando esto con Qsys, necesitarás crear una envoltura TCL para tu núcleo IP. No voy a mostrar una plantilla completa de envoltura, pero a continuación se muestra cómo se añadirí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