1
\$\begingroup\$

I am new to verilog. I'm using this 1:4 demux as described on this webpage (code supplied).

1:4 Demux verilog code

My question is in relation to the select line. I have a soft processor NIOS II on the fpga with an application written in c running on it. How would I control the select line from the NIOS? I presume that you would write a value to some location but I am unsure as to how it would work precisely.

Appreciate and tips of suggestions.

\$\endgroup\$
4
\$\begingroup\$

In order for NIOS to access peripherals in the FPGA, you need to perform a process called "Memory Mapping". Essentially this boils down to building fabric to map the peripheral to an address in the NIOS memory map so that you can access it.

The NIOS processor uses an Avalon-MM data master for accessing all peripherals, so in order to connect the control lines of your demultiplexer, you need to wrap them into an Avalon-MM slave interface which is then connected to the data master and assigned an address.

The simplest way to make the connection is to use an Avalon-MM PIO controller which is basically an IP core which can be used to connect inputs or outputs to the Avalon-MM bus. This is used frequently for mapping external IO pins to NIOS, but can be used for internal connections too.

Alternatively, you can directly create an Avalon-MM interface in your demultiplexer code. You can find the interface specifications here which will tell you what each of the signals do. To help you out, you can use the following Verilog template which I created and use in all of the IP cores I make for use with 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

That template handles byte enables, read and write, and also interrupts. You can strip away stuff like interrupt handlers for something as simple as a demux.

If you are using this with Qsys, you would need to create a TCL wrapper for your IP core. I won't show a full wrapper template, but below is how you would add the Avalon-MM interface and optionally the IRQ interface. I'm showing this because there are lots of different properties for Avalon-MM interfaces, and the ones shown below match the template above and are known to be working.

# 
# 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
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Hello @Tom Carpenter, many thanks for your detailed and helpful reply. I will try to implement your suggestion. \$\endgroup\$ – artic sol Jun 26 '17 at 7:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.