PIO Programming Example 1

In this example we assume that the cpu includes a PIO module controlling separate 32-bit input and output ports, with no edge capture or interrupts enabled. (See also pio_0.v)

When we instantiate the cpu, we connect the input and output ports to the desired devices. For example, we could connect the toggle switches to the input port and connect the output port to the seven-segment display. The actual specification of the cpu might look as follows:

// Connect dip switches to red LEDS
assign LEDR[17:0] = SW[17:0];

wire [31:0] inport, outport;
assign inport[31:21] = 0;
assign inport[20:18] = KEY[3:1];
assign inport[17:0] = SW;

// map to 7-segment displays
hex_7seg dsp7(outport[31:28],HEX7);
hex_7seg dsp6(outport[27:24],HEX6);
hex_7seg dsp5(outport[23:20],HEX5);
hex_7seg dsp4(outport[19:16],HEX4);
hex_7seg dsp3(outport[15:12],HEX3);
hex_7seg dsp2(outport[11:8],HEX2);
hex_7seg dsp1(outport[7:4],HEX1);
hex_7seg dsp0(outport[3:0],HEX0);


// instantiate our cpu
cpu1 our_cpu(
    // 1) global signals:
    .clk(CLOCK_50),
    .reset_n(RST),

     // the_pio_0
     .in_port_to_the_pio_0(inport),
     .out_port_from_the_pio_0(outport)
    );

The PIO core support provides macros for controlling digital output and input.

The following simple program reads the input port and sends the value to the output port:


/*
 * PIO test
 *
 */

#include <stdio.h>
#include <unistd.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"


int main()
{
  int in,  out;
  while (1) 
  {
	  in = IORD_ALTERA_AVALON_PIO_DATA(PIO_0_BASE);
	  out = in;
	  IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, out);
  }
}


The PIO macros are defined in altera_avalon_pio_regs.h. The relevant portion of that file is shown below. The macro IORD_ALTERA_AVALON_PIO_DATA reads the input port, and the macro IOWR_ALTERA_AVALON_PIO_DATA writes the output port.

#define IOADDR_ALTERA_AVALON_PIO_DATA(base)           __IO_CALC_ADDRESS_NATIVE(base, 0)
#define IORD_ALTERA_AVALON_PIO_DATA(base)             IORD(base, 0) 
#define IOWR_ALTERA_AVALON_PIO_DATA(base, data)       IOWR(base, 0, data)

The base address is found in system.h, which is placed in the system description folder of the system library. The relevant portion is shown below. All we need is the base address PIO_0_BASE.

/*
 * pio_0 configuration
 *
 */

#define PIO_0_NAME "/dev/pio_0"
#define PIO_0_TYPE "altera_avalon_pio"
#define PIO_0_BASE 0x00008820
#define PIO_0_SPAN 16
#define PIO_0_DO_TEST_BENCH_WIRING 0
#define PIO_0_DRIVEN_SIM_VALUE 0x0000
#define PIO_0_HAS_TRI 0
#define PIO_0_HAS_OUT 1
#define PIO_0_HAS_IN 1
#define PIO_0_CAPTURE 0
#define PIO_0_EDGE_TYPE "NONE"
#define PIO_0_IRQ_TYPE "NONE"
#define PIO_0_FREQ 50000000

Attachments

pio_0.v
altera_avalon_pio_regs.h
system.h

pio_0.v


// synthesis translate_off
`timescale 1ns / 1ps
// synthesis translate_on

// turn off superfluous verilog processor warnings 
// altera message_level Level1 
// altera message_off 10034 10035 10036 10037 10230 10240 10030 

module pio_0 (
               // inputs:
                address,
                chipselect,
                clk,
                in_port,
                reset_n,
                write_n,
                writedata,

               // outputs:
                out_port,
                readdata
             )
;

  output  [ 31: 0] out_port;
  output  [ 31: 0] readdata;
  input   [  1: 0] address;
  input            chipselect;
  input            clk;
  input   [ 31: 0] in_port;
  input            reset_n;
  input            write_n;
  input   [ 31: 0] writedata;

  wire             clk_en;
  wire    [ 31: 0] data_in;
  reg     [ 31: 0] data_out;
  wire    [ 31: 0] out_port;
  wire    [ 31: 0] read_mux_out;
  reg     [ 31: 0] readdata;
  assign clk_en = 1;
  //s1, which is an e_avalon_slave
  assign read_mux_out = {32 {(address == 0)}} & data_in;
  always @(posedge clk or negedge reset_n)
    begin
      if (reset_n == 0)
          readdata <= 0;
      else if (clk_en)
          readdata <= read_mux_out;
    end


  always @(posedge clk or negedge reset_n)
    begin
      if (reset_n == 0)
          data_out <= 0;
      else if (chipselect && ~write_n && (address == 0))
          data_out <= writedata[31 : 0];
    end


  assign out_port = data_out;
  assign data_in = in_port;

endmodule


altera_avalon_pio_regs.h



#ifndef __ALTERA_AVALON_PIO_REGS_H__
#define __ALTERA_AVALON_PIO_REGS_H__

#include <io.h>

#define IOADDR_ALTERA_AVALON_PIO_DATA(base)           __IO_CALC_ADDRESS_NATIVE(base, 0)
#define IORD_ALTERA_AVALON_PIO_DATA(base)             IORD(base, 0) 
#define IOWR_ALTERA_AVALON_PIO_DATA(base, data)       IOWR(base, 0, data)

#define IOADDR_ALTERA_AVALON_PIO_DIRECTION(base)      __IO_CALC_ADDRESS_NATIVE(base, 1)
#define IORD_ALTERA_AVALON_PIO_DIRECTION(base)        IORD(base, 1) 
#define IOWR_ALTERA_AVALON_PIO_DIRECTION(base, data)  IOWR(base, 1, data)

#define IOADDR_ALTERA_AVALON_PIO_IRQ_MASK(base)       __IO_CALC_ADDRESS_NATIVE(base, 2)
#define IORD_ALTERA_AVALON_PIO_IRQ_MASK(base)         IORD(base, 2) 
#define IOWR_ALTERA_AVALON_PIO_IRQ_MASK(base, data)   IOWR(base, 2, data)

#define IOADDR_ALTERA_AVALON_PIO_EDGE_CAP(base)       __IO_CALC_ADDRESS_NATIVE(base, 3)
#define IORD_ALTERA_AVALON_PIO_EDGE_CAP(base)         IORD(base, 3) 
#define IOWR_ALTERA_AVALON_PIO_EDGE_CAP(base, data)   IOWR(base, 3, data)

#endif /* __ALTERA_AVALON_PIO_REGS_H__ */


system.h


/* system.h
 *
 * Machine generated for a CPU named "cpu_0" as defined in:
 * D:\loomis\sys1\software\hello_world_small_1_syslib\..\..\cpu1.ptf
 *
 * Generated: 2007-05-30 16:16:55.801
 *
 */

#ifndef __SYSTEM_H_
#define __SYSTEM_H_

/*

DO NOT MODIFY THIS FILE

   Changing this file will have subtle consequences
   which will almost certainly lead to a nonfunctioning
   system. If you do modify this file, be aware that your
   changes will be overwritten and lost when this file
   is generated again.

DO NOT MODIFY THIS FILE

*/

/*
 * system configuration
 *
 */

#define ALT_SYSTEM_NAME "cpu1"
#define ALT_CPU_NAME "cpu_0"
#define ALT_CPU_ARCHITECTURE "altera_nios2"
#define ALT_DEVICE_FAMILY "CYCLONEII"
#define ALT_STDIN "/dev/jtag_uart_0"
#define ALT_STDIN_TYPE "altera_avalon_jtag_uart"
#define ALT_STDIN_BASE 0x00008830
#define ALT_STDOUT "/dev/jtag_uart_0"
#define ALT_STDOUT_TYPE "altera_avalon_jtag_uart"
#define ALT_STDOUT_BASE 0x00008830
#define ALT_STDERR "/dev/jtag_uart_0"
#define ALT_STDERR_TYPE "altera_avalon_jtag_uart"
#define ALT_STDERR_BASE 0x00008830
#define ALT_CPU_FREQ 50000000
#define ALT_IRQ_BASE NULL

/*
 * processor configuration
 *
 */

#define NIOS2_CPU_IMPLEMENTATION "fast"
#define NIOS2_BIG_ENDIAN 0

#define NIOS2_ICACHE_SIZE 4096
#define NIOS2_DCACHE_SIZE 2048
#define NIOS2_ICACHE_LINE_SIZE 32
#define NIOS2_ICACHE_LINE_SIZE_LOG2 5
#define NIOS2_DCACHE_LINE_SIZE 4
#define NIOS2_DCACHE_LINE_SIZE_LOG2 2
#define NIOS2_FLUSHDA_SUPPORTED

#define NIOS2_EXCEPTION_ADDR 0x00000020
#define NIOS2_RESET_ADDR 0x00000000
#define NIOS2_BREAK_ADDR 0x00008020

#define NIOS2_HAS_DEBUG_STUB

#define NIOS2_CPU_ID_SIZE 1
#define NIOS2_CPU_ID_VALUE 0

/*
 * A define for each class of peripheral
 *
 */

#define __ALTERA_AVALON_ONCHIP_MEMORY2
#define __ALTERA_AVALON_JTAG_UART
#define __ALTERA_AVALON_TIMER
#define __ALTERA_AVALON_PIO

/*
 * onchip_memory_0 configuration
 *
 */

#define ONCHIP_MEMORY_0_NAME "/dev/onchip_memory_0"
#define ONCHIP_MEMORY_0_TYPE "altera_avalon_onchip_memory2"
#define ONCHIP_MEMORY_0_BASE 0x00000000
#define ONCHIP_MEMORY_0_SPAN 32768
#define ONCHIP_MEMORY_0_ALLOW_MRAM_SIM_CONTENTS_ONLY_FILE 0
#define ONCHIP_MEMORY_0_RAM_BLOCK_TYPE "M4K"
#define ONCHIP_MEMORY_0_INIT_CONTENTS_FILE "onchip_memory_0"
#define ONCHIP_MEMORY_0_NON_DEFAULT_INIT_FILE_ENABLED 0
#define ONCHIP_MEMORY_0_GUI_RAM_BLOCK_TYPE "Automatic"
#define ONCHIP_MEMORY_0_WRITEABLE 1
#define ONCHIP_MEMORY_0_DUAL_PORT 0
#define ONCHIP_MEMORY_0_SIZE_VALUE 32
#define ONCHIP_MEMORY_0_SIZE_MULTIPLE 1024
#define ONCHIP_MEMORY_0_CONTENTS_INFO "QUARTUS_PROJECT_DIR/onchip_memory_0.hex 1180040469 SIMDIR/onchip_memory_0.dat 1180040469"

/*
 * jtag_uart_0 configuration
 *
 */

#define JTAG_UART_0_NAME "/dev/jtag_uart_0"
#define JTAG_UART_0_TYPE "altera_avalon_jtag_uart"
#define JTAG_UART_0_BASE 0x00008830
#define JTAG_UART_0_SPAN 8
#define JTAG_UART_0_IRQ 0
#define JTAG_UART_0_WRITE_DEPTH 64
#define JTAG_UART_0_READ_DEPTH 64
#define JTAG_UART_0_WRITE_THRESHOLD 8
#define JTAG_UART_0_READ_THRESHOLD 8
#define JTAG_UART_0_READ_CHAR_STREAM ""
#define JTAG_UART_0_SHOWASCII 1
#define JTAG_UART_0_READ_LE 0
#define JTAG_UART_0_WRITE_LE 0
#define JTAG_UART_0_ALTERA_SHOW_UNRELEASED_JTAG_UART_FEATURES 0

/*
 * timer_0 configuration
 *
 */

#define TIMER_0_NAME "/dev/timer_0"
#define TIMER_0_TYPE "altera_avalon_timer"
#define TIMER_0_BASE 0x00008800
#define TIMER_0_SPAN 32
#define TIMER_0_IRQ 1
#define TIMER_0_ALWAYS_RUN 0
#define TIMER_0_FIXED_PERIOD 0
#define TIMER_0_SNAPSHOT 1
#define TIMER_0_PERIOD 1
#define TIMER_0_PERIOD_UNITS "ms"
#define TIMER_0_RESET_OUTPUT 0
#define TIMER_0_TIMEOUT_PULSE_OUTPUT 0
#define TIMER_0_MULT 0.001
#define TIMER_0_FREQ 50000000

/*
 * pio_0 configuration
 *
 */

#define PIO_0_NAME "/dev/pio_0"
#define PIO_0_TYPE "altera_avalon_pio"
#define PIO_0_BASE 0x00008820
#define PIO_0_SPAN 16
#define PIO_0_DO_TEST_BENCH_WIRING 0
#define PIO_0_DRIVEN_SIM_VALUE 0x0000
#define PIO_0_HAS_TRI 0
#define PIO_0_HAS_OUT 1
#define PIO_0_HAS_IN 1
#define PIO_0_CAPTURE 0
#define PIO_0_EDGE_TYPE "NONE"
#define PIO_0_IRQ_TYPE "NONE"
#define PIO_0_FREQ 50000000

/*
 * system library configuration
 *
 */

#define ALT_MAX_FD 4
#define ALT_SYS_CLK none
#define ALT_TIMESTAMP_CLK none

/*
 * Devices associated with code sections.
 *
 */

#define ALT_TEXT_DEVICE       ONCHIP_MEMORY_0
#define ALT_RODATA_DEVICE     ONCHIP_MEMORY_0
#define ALT_RWDATA_DEVICE     ONCHIP_MEMORY_0
#define ALT_EXCEPTIONS_DEVICE ONCHIP_MEMORY_0
#define ALT_RESET_DEVICE      ONCHIP_MEMORY_0

/*
 * The text section is initialised so no bootloader will be required.
 * Set a variable to tell crt0.S to provide code at the reset address and
 * to initialise rwdata if appropriate.
 */

#define ALT_NO_BOOTLOADER


#endif /* __SYSTEM_H_ */


Maintained by John Loomis, last updated 31 May 2007