OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_47/] [or1ksim/] [peripheral/] [gpio.c] - Diff between revs 1419 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 1419 Rev 1765
/* gpio.h -- GPIO code simulation
/* gpio.h -- GPIO code simulation
   Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org
   Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org
 
 
   This file is part of OpenRISC 1000 Architectural Simulator.
   This file is part of OpenRISC 1000 Architectural Simulator.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
*/
#include <string.h>
#include <string.h>
 
 
#include "config.h"
#include "config.h"
 
 
#ifdef HAVE_INTTYPES_H
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#include <inttypes.h>
#endif
#endif
 
 
#include "port.h"
#include "port.h"
#include "arch.h"
#include "arch.h"
#include "abstract.h"
#include "abstract.h"
#include "gpio.h"
#include "gpio.h"
#include "gpio_i.h"
#include "gpio_i.h"
#include "sim-config.h"
#include "sim-config.h"
#include "pic.h"
#include "pic.h"
#include "vapi.h"
#include "vapi.h"
#include "debug.h"
#include "debug.h"
#include "sched.h"
#include "sched.h"
 
 
static void gpio_vapi_read( unsigned long id, unsigned long data, void *dat );
static void gpio_vapi_read( unsigned long id, unsigned long data, void *dat );
static uint32_t gpio_read32( oraddr_t addr, void *dat );
static uint32_t gpio_read32( oraddr_t addr, void *dat );
static void gpio_write32( oraddr_t addr, uint32_t value, void *dat );
static void gpio_write32( oraddr_t addr, uint32_t value, void *dat );
 
 
static void gpio_external_clock( unsigned long value, struct gpio_device *gpio );
static void gpio_external_clock( unsigned long value, struct gpio_device *gpio );
static void gpio_device_clock( struct gpio_device *gpio );
static void gpio_device_clock( struct gpio_device *gpio );
 
 
/* Initialize all parameters and state */
/* Initialize all parameters and state */
void gpio_reset( void *dat )
void gpio_reset( void *dat )
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
 
 
  if ( gpio->baseaddr != 0 ) {
  if ( gpio->baseaddr != 0 ) {
    /* Possibly connect to VAPI */
    /* Possibly connect to VAPI */
    if ( gpio->base_vapi_id ) {
    if ( gpio->base_vapi_id ) {
      vapi_install_multi_handler( gpio->base_vapi_id, GPIO_NUM_VAPI_IDS, gpio_vapi_read, dat );
      vapi_install_multi_handler( gpio->base_vapi_id, GPIO_NUM_VAPI_IDS, gpio_vapi_read, dat );
    }
    }
  }
  }
}
}
 
 
 
 
/* Dump status */
/* Dump status */
void gpio_status( void *dat )
void gpio_status( void *dat )
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
 
 
  if ( gpio->baseaddr == 0 )
  if ( gpio->baseaddr == 0 )
    return;
    return;
 
 
  PRINTF( "\nGPIO at 0x%"PRIxADDR":\n", gpio->baseaddr );
  PRINTF( "\nGPIO at 0x%"PRIxADDR":\n", gpio->baseaddr );
  PRINTF( "RGPIO_IN     : 0x%08lX\n", gpio->curr.in );
  PRINTF( "RGPIO_IN     : 0x%08lX\n", gpio->curr.in );
  PRINTF( "RGPIO_OUT    : 0x%08lX\n", gpio->curr.out );
  PRINTF( "RGPIO_OUT    : 0x%08lX\n", gpio->curr.out );
  PRINTF( "RGPIO_OE     : 0x%08lX\n", gpio->curr.oe );
  PRINTF( "RGPIO_OE     : 0x%08lX\n", gpio->curr.oe );
  PRINTF( "RGPIO_INTE   : 0x%08lX\n", gpio->curr.inte );
  PRINTF( "RGPIO_INTE   : 0x%08lX\n", gpio->curr.inte );
  PRINTF( "RGPIO_PTRIG  : 0x%08lX\n", gpio->curr.ptrig );
  PRINTF( "RGPIO_PTRIG  : 0x%08lX\n", gpio->curr.ptrig );
  PRINTF( "RGPIO_AUX    : 0x%08lX\n", gpio->curr.aux );
  PRINTF( "RGPIO_AUX    : 0x%08lX\n", gpio->curr.aux );
  PRINTF( "RGPIO_CTRL   : 0x%08lX\n", gpio->curr.ctrl );
  PRINTF( "RGPIO_CTRL   : 0x%08lX\n", gpio->curr.ctrl );
  PRINTF( "RGPIO_INTS   : 0x%08lX\n", gpio->curr.ints );
  PRINTF( "RGPIO_INTS   : 0x%08lX\n", gpio->curr.ints );
}
}
 
 
 
 
/* Wishbone read */
/* Wishbone read */
uint32_t gpio_read32( oraddr_t addr, void *dat )
uint32_t gpio_read32( oraddr_t addr, void *dat )
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
 
 
  addr -= gpio->baseaddr;
  addr -= gpio->baseaddr;
 
 
  switch( addr ) {
  switch( addr ) {
  case RGPIO_IN: return gpio->curr.in | gpio->curr.out;
  case RGPIO_IN: return gpio->curr.in | gpio->curr.out;
  case RGPIO_OUT: return gpio->curr.out;
  case RGPIO_OUT: return gpio->curr.out;
  case RGPIO_OE: return gpio->curr.oe;
  case RGPIO_OE: return gpio->curr.oe;
  case RGPIO_INTE: return gpio->curr.inte;
  case RGPIO_INTE: return gpio->curr.inte;
  case RGPIO_PTRIG: return gpio->curr.ptrig;
  case RGPIO_PTRIG: return gpio->curr.ptrig;
  case RGPIO_AUX: return gpio->curr.aux;
  case RGPIO_AUX: return gpio->curr.aux;
  case RGPIO_CTRL: return gpio->curr.ctrl;
  case RGPIO_CTRL: return gpio->curr.ctrl;
  case RGPIO_INTS: return gpio->curr.ints;
  case RGPIO_INTS: return gpio->curr.ints;
  }
  }
 
 
  return 0;
  return 0;
}
}
 
 
 
 
/* Wishbone write */
/* Wishbone write */
void gpio_write32( oraddr_t addr, uint32_t value, void *dat )
void gpio_write32( oraddr_t addr, uint32_t value, void *dat )
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
 
 
  addr -= gpio->baseaddr;
  addr -= gpio->baseaddr;
 
 
  switch( addr ) {
  switch( addr ) {
  case RGPIO_IN: debug( 5, "GPIO: Cannot write to RGPIO_IN\n" ); break;
  case RGPIO_IN: debug( 5, "GPIO: Cannot write to RGPIO_IN\n" ); break;
  case RGPIO_OUT: gpio->next.out = value; break;
  case RGPIO_OUT: gpio->next.out = value; break;
  case RGPIO_OE: gpio->next.oe = value; break;
  case RGPIO_OE: gpio->next.oe = value; break;
  case RGPIO_INTE: gpio->next.inte = value; break;
  case RGPIO_INTE: gpio->next.inte = value; break;
  case RGPIO_PTRIG: gpio->next.ptrig = value; break;
  case RGPIO_PTRIG: gpio->next.ptrig = value; break;
  case RGPIO_AUX: gpio->next.aux = value; break;
  case RGPIO_AUX: gpio->next.aux = value; break;
  case RGPIO_CTRL: gpio->next.ctrl = value; break;
  case RGPIO_CTRL: gpio->next.ctrl = value; break;
  case RGPIO_INTS: gpio->next.ints = value; break;
  case RGPIO_INTS: gpio->next.ints = value; break;
  }
  }
}
}
 
 
 
 
/* Input from "outside world" */
/* Input from "outside world" */
void gpio_vapi_read( unsigned long id, unsigned long data, void *dat )
void gpio_vapi_read( unsigned long id, unsigned long data, void *dat )
{
{
  unsigned which;
  unsigned which;
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
 
 
  debug( 5, "GPIO: id %08lx, data %08lx\n", id, data );
  debug( 5, "GPIO: id %08lx, data %08lx\n", id, data );
 
 
  which = id - gpio->base_vapi_id;
  which = id - gpio->base_vapi_id;
 
 
  switch( which ) {
  switch( which ) {
  case GPIO_VAPI_DATA:
  case GPIO_VAPI_DATA:
    debug( 4, "GPIO: Next input from VAPI = 0x%08lx (RGPIO_OE = 0x%08lx)\n",
    debug( 4, "GPIO: Next input from VAPI = 0x%08lx (RGPIO_OE = 0x%08lx)\n",
           data, gpio->next.oe );
           data, gpio->next.oe );
    gpio->next.in = data;
    gpio->next.in = data;
    break;
    break;
  case GPIO_VAPI_AUX:
  case GPIO_VAPI_AUX:
    gpio->auxiliary_inputs = data;
    gpio->auxiliary_inputs = data;
    break;
    break;
  case GPIO_VAPI_RGPIO_OE:
  case GPIO_VAPI_RGPIO_OE:
    gpio->next.oe = data;
    gpio->next.oe = data;
    break;
    break;
  case GPIO_VAPI_RGPIO_INTE:
  case GPIO_VAPI_RGPIO_INTE:
    gpio->next.inte = data;
    gpio->next.inte = data;
    break;
    break;
  case GPIO_VAPI_RGPIO_PTRIG:
  case GPIO_VAPI_RGPIO_PTRIG:
    gpio->next.ptrig = data;
    gpio->next.ptrig = data;
    break;
    break;
  case GPIO_VAPI_RGPIO_AUX:
  case GPIO_VAPI_RGPIO_AUX:
    gpio->next.aux = data;
    gpio->next.aux = data;
    break;
    break;
  case GPIO_VAPI_RGPIO_CTRL:
  case GPIO_VAPI_RGPIO_CTRL:
    gpio->next.ctrl = data;
    gpio->next.ctrl = data;
    break;
    break;
  case GPIO_VAPI_CLOCK:
  case GPIO_VAPI_CLOCK:
    gpio_external_clock( data, gpio );
    gpio_external_clock( data, gpio );
    break;
    break;
  }
  }
 
 
  /* Clock the device */
  /* Clock the device */
  if ( !(gpio->curr.ctrl & RGPIO_CTRL_ECLK) )
  if ( !(gpio->curr.ctrl & RGPIO_CTRL_ECLK) )
    gpio_device_clock( gpio );
    gpio_device_clock( gpio );
}
}
 
 
/* External Clock. */
/* External Clock. */
static void gpio_external_clock( unsigned long value, struct gpio_device *gpio )
static void gpio_external_clock( unsigned long value, struct gpio_device *gpio )
{
{
  int use_external_clock = ((gpio->curr.ctrl & RGPIO_CTRL_ECLK) == RGPIO_CTRL_ECLK);
  int use_external_clock = ((gpio->curr.ctrl & RGPIO_CTRL_ECLK) == RGPIO_CTRL_ECLK);
  int negative_edge = ((gpio->curr.ctrl & RGPIO_CTRL_NEC) == RGPIO_CTRL_NEC);
  int negative_edge = ((gpio->curr.ctrl & RGPIO_CTRL_NEC) == RGPIO_CTRL_NEC);
 
 
  /* "Normalize" clock value */
  /* "Normalize" clock value */
  value = (value != 0);
  value = (value != 0);
 
 
  gpio->next.external_clock = value;
  gpio->next.external_clock = value;
 
 
  if ( use_external_clock && (gpio->next.external_clock != gpio->curr.external_clock) && (value != negative_edge) )
  if ( use_external_clock && (gpio->next.external_clock != gpio->curr.external_clock) && (value != negative_edge) )
    /* Make sure that in vapi_read, we don't clock the device */
    /* Make sure that in vapi_read, we don't clock the device */
    if ( gpio->curr.ctrl & RGPIO_CTRL_ECLK )
    if ( gpio->curr.ctrl & RGPIO_CTRL_ECLK )
      gpio_device_clock( gpio );
      gpio_device_clock( gpio );
}
}
 
 
/* Report an interrupt to the sim */
/* Report an interrupt to the sim */
void gpio_do_int( void *dat )
void gpio_do_int( void *dat )
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
 
 
  report_interrupt( gpio->irq );
  report_interrupt( gpio->irq );
}
}
 
 
/* Clock as handld by one device. */
/* Clock as handld by one device. */
static void gpio_device_clock( struct gpio_device *gpio )
static void gpio_device_clock( struct gpio_device *gpio )
{
{
  /* Calculate new inputs and outputs */
  /* Calculate new inputs and outputs */
  gpio->next.in &= ~gpio->next.oe; /* Only input bits */
  gpio->next.in &= ~gpio->next.oe; /* Only input bits */
  /* Replace requested output bits with aux input */
  /* Replace requested output bits with aux input */
  gpio->next.out = (gpio->next.out & ~gpio->next.aux) | (gpio->auxiliary_inputs & gpio->next.aux);
  gpio->next.out = (gpio->next.out & ~gpio->next.aux) | (gpio->auxiliary_inputs & gpio->next.aux);
  gpio->next.out &= gpio->next.oe; /* Only output-enabled bits */
  gpio->next.out &= gpio->next.oe; /* Only output-enabled bits */
 
 
  /* If any outputs changed, notify the world (i.e. vapi) */
  /* If any outputs changed, notify the world (i.e. vapi) */
  if ( gpio->next.out != gpio->curr.out ) {
  if ( gpio->next.out != gpio->curr.out ) {
    debug( 4, "GPIO: New output 0x%08lx, RGPIO_OE = 0x%08lx\n", gpio->next.out,
    debug( 4, "GPIO: New output 0x%08lx, RGPIO_OE = 0x%08lx\n", gpio->next.out,
           gpio->next.oe );
           gpio->next.oe );
    if ( gpio->base_vapi_id )
    if ( gpio->base_vapi_id )
      vapi_send( gpio->base_vapi_id + GPIO_VAPI_DATA, gpio->next.out );
      vapi_send( gpio->base_vapi_id + GPIO_VAPI_DATA, gpio->next.out );
  }
  }
 
 
  /* If any inputs changed and interrupt enabled, generate interrupt */
  /* If any inputs changed and interrupt enabled, generate interrupt */
  if ( gpio->next.in != gpio->curr.in ) {
  if ( gpio->next.in != gpio->curr.in ) {
    debug( 4, "GPIO: New input 0x%08lx\n", gpio->next.in );
    debug( 4, "GPIO: New input 0x%08lx\n", gpio->next.in );
 
 
    if ( gpio->next.ctrl & RGPIO_CTRL_INTE ) {
    if ( gpio->next.ctrl & RGPIO_CTRL_INTE ) {
      unsigned changed_bits = gpio->next.in ^ gpio->curr.in; /* inputs that have changed */
      unsigned changed_bits = gpio->next.in ^ gpio->curr.in; /* inputs that have changed */
      unsigned set_bits = changed_bits & gpio->next.in; /* inputs that have been set */
      unsigned set_bits = changed_bits & gpio->next.in; /* inputs that have been set */
      unsigned cleared_bits = changed_bits & gpio->curr.in; /* inputs that have been cleared */
      unsigned cleared_bits = changed_bits & gpio->curr.in; /* inputs that have been cleared */
      unsigned relevant_bits = (gpio->next.ptrig & set_bits) | (~gpio->next.ptrig & cleared_bits);
      unsigned relevant_bits = (gpio->next.ptrig & set_bits) | (~gpio->next.ptrig & cleared_bits);
 
 
      if ( relevant_bits & gpio->next.inte ) {
      if ( relevant_bits & gpio->next.inte ) {
        debug( 3, "GPIO: Reporting interrupt %d\n", gpio->irq );
        debug( 3, "GPIO: Reporting interrupt %d\n", gpio->irq );
        gpio->next.ctrl |= RGPIO_CTRL_INTS;
        gpio->next.ctrl |= RGPIO_CTRL_INTS;
        gpio->next.ints |= relevant_bits & gpio->next.inte;
        gpio->next.ints |= relevant_bits & gpio->next.inte;
        /* Since we can't report an interrupt during a readmem/writemem
        /* Since we can't report an interrupt during a readmem/writemem
         * schedule the scheduler to do it.  Read the comment above
         * schedule the scheduler to do it.  Read the comment above
         * report_interrupt in pic/pic.c */
         * report_interrupt in pic/pic.c */
        SCHED_ADD( gpio_do_int, gpio, 1 );
        SCHED_ADD( gpio_do_int, gpio, 1 );
      }
      }
    }
    }
  }
  }
 
 
  /* Switch to values for next clock */
  /* Switch to values for next clock */
  memcpy( &(gpio->curr), &(gpio->next), sizeof(gpio->curr) );
  memcpy( &(gpio->curr), &(gpio->next), sizeof(gpio->curr) );
}
}
 
 
/*---------------------------------------------------[ GPIO configuration ]---*/
/*---------------------------------------------------[ GPIO configuration ]---*/
void gpio_baseaddr(union param_val val, void *dat)
void gpio_baseaddr(union param_val val, void *dat)
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
  gpio->baseaddr = val.addr_val;
  gpio->baseaddr = val.addr_val;
}
}
 
 
void gpio_irq(union param_val val, void *dat)
void gpio_irq(union param_val val, void *dat)
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
  gpio->irq = val.int_val;
  gpio->irq = val.int_val;
}
}
 
 
void gpio_base_vapi_id(union param_val val, void *dat)
void gpio_base_vapi_id(union param_val val, void *dat)
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
  gpio->base_vapi_id = val.int_val;
  gpio->base_vapi_id = val.int_val;
}
}
 
 
void *gpio_sec_start(void)
void *gpio_sec_start(void)
{
{
  struct gpio_device *new = malloc(sizeof(struct gpio_device));
  struct gpio_device *new = malloc(sizeof(struct gpio_device));
 
 
  if(!new) {
  if(!new) {
    fprintf(stderr, "Peripheral gpio: Run out of memory\n");
    fprintf(stderr, "Peripheral gpio: Run out of memory\n");
    exit(-1);
    exit(-1);
  }
  }
 
 
  new->auxiliary_inputs = 0;
  new->auxiliary_inputs = 0;
  memset(&new->curr, 0, sizeof(new->curr));
  memset(&new->curr, 0, sizeof(new->curr));
  memset(&new->next, 0, sizeof(new->next));
  memset(&new->next, 0, sizeof(new->next));
 
 
  return new;
  return new;
}
}
 
 
void gpio_sec_end(void *dat)
void gpio_sec_end(void *dat)
{
{
  struct gpio_device *gpio = dat;
  struct gpio_device *gpio = dat;
 
 
  /* Register memory range */
  /* Register memory range */
  register_memoryarea( gpio->baseaddr, GPIO_ADDR_SPACE, 4, 0, gpio_read32, gpio_write32, dat );
  register_memoryarea( gpio->baseaddr, GPIO_ADDR_SPACE, 4, 0, gpio_read32, gpio_write32, dat );
 
 
  reg_sim_reset(gpio_reset, dat);
  reg_sim_reset(gpio_reset, dat);
  reg_sim_stat(gpio_status, dat);
  reg_sim_stat(gpio_status, dat);
}
}
 
 
void reg_gpio_sec(void)
void reg_gpio_sec(void)
{
{
  struct config_section *sec = reg_config_sec("gpio", gpio_sec_start, gpio_sec_end);
  struct config_section *sec = reg_config_sec("gpio", gpio_sec_start, gpio_sec_end);
 
 
  reg_config_param(sec, "baseaddr", paramt_addr, gpio_baseaddr);
  reg_config_param(sec, "baseaddr", paramt_addr, gpio_baseaddr);
  reg_config_param(sec, "irq", paramt_int, gpio_irq);
  reg_config_param(sec, "irq", paramt_int, gpio_irq);
  reg_config_param(sec, "base_vapi_id", paramt_int, gpio_base_vapi_id);
  reg_config_param(sec, "base_vapi_id", paramt_int, gpio_base_vapi_id);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.