Programmable IO

The Programmable IO IP Core is a versatile and highly configurable module designed for generating and controlling low-speed digital interfaces. It features an internal state machine that can be programmed to drive the IO signal in various sequences. This allows the IP core to support a wide range of protocols and custom interfaces by bit-banging the signal according to the programmed commands.

State Machine

The core of the Programmable IO IP Core is its internal state machine, which operates in four distinct states:

  1. Signal High (HIGH)

    • In this state, the IO signal is set to a high logic level (1).

    • This state is used when the protocol requires a high signal on the IO line.

    • Command value: 0x0

  2. Signal Low (LOW)

    • In this state, the IO signal is set to a low logic level (0).

    • This state is used when the protocol requires a low signal on the IO line.

    • Command value: 0x1

  3. Wait (WAIT)

    • The WAIT state introduces a delay in the signal transition.

    • It is useful for timing control, ensuring that the signal remains in its current state for a specified period.

    • Command value: 0x2

  4. Read (READ)

    • In the READ state, the core samples the IO signal and returns its value.

    • This state is essential for protocols that require reading data from the IO line.

    • Command value: 0x3

Command Interface

The state machine transitions between these states based on commands received via a control interface. Each command specifies the next state and any necessary parameters, such as the duration of the WAIT state or the number of pins to read in the READ state.

Example Commands:

  • SET_HIGH: Transition to the HIGH state.

  • SET_LOW: Transition to the LOW state.

  • SET_WAIT(n): Enter the WAIT state for ‘n’ clock cycles.

  • READ: Transition to the READ state and capture the current IO signal.

Usage

To utilize the Programmable IO IP Core for bit-banging various low-speed interfaces, users must configure the state machine with a sequence of commands that reflect the desired protocol’s timing and signal transitions. The commands can be sent in real-time, allowing dynamic reconfiguration based on operational needs.

Example Sequence:

  1. SET_LOW: Start with the signal low.

  2. SET_WAIT(10): Wait for 10 clock cycles.

  3. SET_HIGH: Set the signal high.

  4. SET_WAIT(5): Wait for 5 clock cycles.

  5. READ: Read the signal to capture the input value.

This sequence could be part of a protocol where the signal is pulled low, held for a period, then raised, and a value is read from the line.

Applications

The flexibility of the Programmable IO IP Core makes it suitable for a variety of applications, including but not limited to:

  • Custom serial communication protocols

  • GPIO signal manipulation

  • Interface with legacy hardware with specific timing requirements

  • Prototyping new digital communication standards

Configuration

Available bus architectures:

  • APB3

  • Wishbone

  • AvalonMM

By default, all buses are defined with 12 bit address and 32 bit data width.

Parameter

Pio.Parameter defines the IO pins of the programmable IO controller.

Pio.Parameter

Name

Type

Description

Default

Width

Int

Number of IO pins. Must be greater then 0.

PioCtrl.InitParameter defines the initialization values for certian registers.

PioCtrl.InitParameter

Name

Type

Description

Default

clockDivider

Int

Initialization value of the internal clock divider

0

readDelay

Int

Initialization value of the register which delays read actions

0

Note

Parameter in InitParameter with a value “0” are equal to disabled. This allows to only set certain parameters.

PioCtrl.MemoryMappedParameter defines the FIFO width.

PioCtrl.MemoryMappedParameter

Name

Type

Description

Default

commandFifoDepth

Int

FIFO depth for incoming commands.

16

readFifoDepth

Int

FIFO depth for outgoing read results.

8

PioCtrl.PermissionParameter defines the permission rules for bus access.

PioCtrl.PermissionParameter

Name

Type

Description

Default

busCanWriteClockDividerConfig

Boolean

Toggles bus access to the clock divider.

PioCtrl.Parameter configures the programmable IO controller. It uses Pio.Parameter as parameter.

PioCtrl.Parameter

Name

Type

Description

Default

io

Pio.Parameter

Class with IO parameters

readBufferDepth

Int

Number of registers on the input path to stabilize read values. Disabled when 0.

2

init

PioCtrl.InitParameter

Class to parametrize the initialization values.

InitParameter.disabled

permission

PioCtrl.PermissionParameter

Class to set bus access.

PermissionParameter.granted

memory

PioCtrl.MemoryMappedParameter

Class to define FIFO depth.

MemoryMappedParameter.default

dataWidth

Int

Width of the data field used in the command FIFO to pass additional information to the controller.

24

clockDividerWidth

Int

Width of the clock divider counter.

20

readDelayWidth

Int

Width of the read delay counter.

8

PioCtrl.Parameter has some functions with pre-predefined parameters for common use-cases.

object Parameter {
  def default(pins: Int = 1) =
    Parameter(Pio.Parameter(pins))
  def light(pins: Int = 1) =
    Parameter(Pio.Parameter(pins), memory = MemoryMappedParameter.lightweight, dataWidth = 16)
}

Register Mapping

IP Identification:

The register map starts with an IP Identification block to provide all information about the underlying IP core to software drivers. This allows to provide backwards compatible drivers.

IP Identification Registers

Address

Bit

Field

Default

Permission

Description

0x000

31 - 24

API

0x0

Rx

API version of the implemented IP Identification.

23 - 16

Length

0x8

Rx

Length of the IP Identification block in Bytes.

15 - 0

ID

0x1

Rx

IP value of this IP core.

0x004

31 - 24

Major Version

0x1

Rx

Major number if this IP core. Version schema is major.minor.patch.

23 - 16

Minor Version

0x0

Rx

Minor number if this IP core. Version schema is major.minor.patch.

15 - 0

Patch Version

0x0

Rx

Patch number if this IP core. Version schema is major.minor.patch.

Self Disclosure:

This block discloses information about the IP core to software drivers to simplify them.

Self Disclosure Registers

Address

Bit

Field

Default

Permission

Description

0x008

31 - 24

readBufferDepth

Rx

Number of registers on the input path to stabilize read values.

23 - 16

clockDividerWidth

Rx

Width of the clock divider counter.

15 - 8

dataWidth

Rx

Width of the data field used in the command FIFO to pass additional information to the controller.

7 - 0

IO width

Rx

Number of IO pins.

0x00C

15 - 8

readFifoDepth

Rx

Depth of the read FIFO.

7 - 0

commandFifoDepth

Rx

Depth of the command FIFO.

0x010

0

busCanWriteClockDividerConfig

Rx

Flag whether the clock divider is writable.

Command and Read FIFO:

Command and Read FIFO

Address

Bit

Field

Default

Permission

Description

0x014

16

validBit

Rx

This bit contains a 1 when the result FIFO returned valid payload.

15 - 0

resultFifo

Rx

Payload from the result FIFO.

0x014

31 - 0

commandFifo

xW

Sends a command to the controller with the following payload:
  • Lower two bits define the command.

  • Decimal number of the pin.

  • Additional data.

0x018

31 - 24

occupancy

Rx

Number of occupied slots in the result FIFO.

23 - 16

vacancy

Rx

Number of empty slots in the command FIFO.

Clock Divider and Read Delay:

Clock Divider and Read Delay

Address

Bit

Field

Default

Permission

Description

0x01C

clockDividerWidth - 0

clockDividerValue

Depends on PioCtrl.InitParameter

RW or Rx

Value for the clock divider counter to divide down the input clock.

0x020

readDelayWidth - 0

ReadDelayValue

Depends on PioCtrl.InitParameter

RW or Rx

Number of cycles to delay during the read action.