URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [branches/] [stable_0_1_x/] [or1ksim/] [peripheral/] [gpio.c] - Rev 1771
Go to most recent revision | Compare with Previous | Blame | View Log
/* gpio.h -- GPIO code simulation Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org This file is part of OpenRISC 1000 Architectural Simulator. 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <string.h> #include "config.h" #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #include "port.h" #include "arch.h" #include "abstract.h" #include "gpio.h" #include "gpio_i.h" #include "sim-config.h" #include "pic.h" #include "vapi.h" #include "debug.h" static struct gpio_device gpios[MAX_GPIOS]; static void gpio_vapi_read( unsigned long id, unsigned long data ); static uint32_t gpio_read32( oraddr_t addr ); static void gpio_write32( oraddr_t addr, uint32_t value ); static void gpio_external_clock( unsigned long value ); static void gpio_device_clock( struct gpio_device *gpio ); static int gpio_find_device( oraddr_t addr, struct gpio_device **gpio, oraddr_t *reladdr ); static struct gpio_device *gpio_find_vapi_device( unsigned long id, unsigned *which_vapi ); /* Initialize all parameters and state */ void gpio_reset( void ) { static int first_time = 1; unsigned i; if ( first_time ) { memset( gpios, 0, sizeof(gpios) ); first_time = 0; } for ( i = 0; i < config.ngpios; ++ i ) { struct gpio_device *gpio = &(gpios[i]); gpio->gpio_number = i; gpio->baseaddr = config.gpios[i].baseaddr; if ( gpio->baseaddr != 0 ) { /* Get IRQ */ gpio->irq = config.gpios[i].irq; /* Register memory range */ register_memoryarea( gpio->baseaddr, GPIO_ADDR_SPACE, 4, 0, gpio_read32, gpio_write32 ); /* Possibly connect to VAPI */ if ( config.gpios[i].base_vapi_id ) { gpio->base_vapi_id = config.gpios[i].base_vapi_id; vapi_install_multi_handler( gpio->base_vapi_id, GPIO_NUM_VAPI_IDS, gpio_vapi_read ); } } } } /* Dump status */ void gpio_status( void ) { unsigned i; for ( i = 0; i < config.ngpios; ++ i ) { struct gpio_device *gpio = &(gpios[i]); if ( gpio->baseaddr == 0 ) continue; PRINTF( "\nGPIO %u at 0x%"PRIxADDR":\n", i, gpio->baseaddr ); PRINTF( "RGPIO_IN : 0x%08lX\n", gpio->curr.in ); PRINTF( "RGPIO_OUT : 0x%08lX\n", gpio->curr.out ); PRINTF( "RGPIO_OE : 0x%08lX\n", gpio->curr.oe ); PRINTF( "RGPIO_INTE : 0x%08lX\n", gpio->curr.inte ); PRINTF( "RGPIO_PTRIG : 0x%08lX\n", gpio->curr.ptrig ); PRINTF( "RGPIO_AUX : 0x%08lX\n", gpio->curr.aux ); PRINTF( "RGPIO_CTRL : 0x%08lX\n", gpio->curr.ctrl ); PRINTF( "RGPIO_INTS : 0x%08lX\n", gpio->curr.ints ); } } /* Convert a memory address to a device struct and relative address. * Return nonzero on success */ int gpio_find_device( oraddr_t addr, struct gpio_device **gpio, oraddr_t *reladdr ) { unsigned i; *gpio = NULL; for ( i = 0; i < config.ngpios && *gpio == NULL; ++ i ) { if ( (addr >= gpios[i].baseaddr) && (addr < gpios[i].baseaddr + GPIO_ADDR_SPACE) ) *gpio = &(gpios[i]); } /* verify we found a device */ if ( *gpio == NULL ) return 0; /* Verify legal address */ if ( (addr - (*gpio)->baseaddr) % 4 != 0 ) return 0; *reladdr = addr - (*gpio)->baseaddr; return 1; } /* Find device by vapi id */ struct gpio_device *gpio_find_vapi_device( unsigned long id, unsigned *which ) { unsigned i; for ( i = 0; i < config.ngpios; ++ i ) if ( (id >= gpios[i].base_vapi_id) && (id < gpios[i].base_vapi_id + GPIO_NUM_VAPI_IDS) ) { *which = id - gpios[i].base_vapi_id; return &(gpios[i]); } return NULL; } /* Wishbone read */ uint32_t gpio_read32( oraddr_t addr ) { struct gpio_device *gpio; if ( !gpio_find_device( addr, &gpio, &addr ) ) { debug( 2, "gpio_read32( 0x%"PRIxADDR" ): Not in registered range(s)\n", addr ); return 0; } switch( addr ) { case RGPIO_IN: return gpio->curr.in | gpio->curr.out; case RGPIO_OUT: return gpio->curr.out; case RGPIO_OE: return gpio->curr.oe; case RGPIO_INTE: return gpio->curr.inte; case RGPIO_PTRIG: return gpio->curr.ptrig; case RGPIO_AUX: return gpio->curr.aux; case RGPIO_CTRL: return gpio->curr.ctrl; case RGPIO_INTS: return gpio->curr.ints; } } /* Wishbone write */ void gpio_write32( oraddr_t addr, uint32_t value ) { struct gpio_device *gpio; if ( !gpio_find_device( addr, &gpio, &addr ) ) { debug( 2, "gpio_write32( 0x%"PRIxADDR" ): Not in registered range(s)\n", addr ); return; } switch( addr ) { case RGPIO_IN: debug( 5, "GPIO: Cannot write to RGPIO_IN\n" ); break; case RGPIO_OUT: gpio->next.out = value; break; case RGPIO_OE: gpio->next.oe = value; break; case RGPIO_INTE: gpio->next.inte = value; break; case RGPIO_PTRIG: gpio->next.ptrig = value; break; case RGPIO_AUX: gpio->next.aux = value; break; case RGPIO_CTRL: gpio->next.ctrl = value; break; case RGPIO_INTS: gpio->next.ints = value; break; } } /* Input from "outside world" */ void gpio_vapi_read( unsigned long id, unsigned long data ) { unsigned which; struct gpio_device *gpio = gpio_find_vapi_device( id, &which ); debug( 5, "GPIO: id %08lx, data %08lx\n", id, data ); if ( !gpio ) { debug( 1, "GPIO: VAPI ID %08lx is not ours!\n", id ); return; } switch( which ) { case GPIO_VAPI_DATA: debug( 4, "GPIO: Next input from VAPI = 0x%08lx (RGPIO_OE = 0x%08lx)\n", data, gpio->next.oe ); gpio->next.in = data; break; case GPIO_VAPI_AUX: gpio->auxiliary_inputs = data; break; case GPIO_VAPI_RGPIO_OE: gpio->next.oe = data; break; case GPIO_VAPI_RGPIO_INTE: gpio->next.inte = data; break; case GPIO_VAPI_RGPIO_PTRIG: gpio->next.ptrig = data; break; case GPIO_VAPI_RGPIO_AUX: gpio->next.aux = data; break; case GPIO_VAPI_RGPIO_CTRL: gpio->next.ctrl = data; break; case GPIO_VAPI_CLOCK: gpio_external_clock( data ); break; } } /* System Clock. */ void gpio_clock( void ) { unsigned i; for ( i = 0; i < config.ngpios; ++ i ) if ( !(gpios[i].curr.ctrl & RGPIO_CTRL_ECLK) ) gpio_device_clock( &(gpios[i]) ); } /* External Clock. */ void gpio_external_clock( unsigned long value ) { unsigned i; /* "Normalize" clock value */ value = (value != 0); for ( i = 0; i < config.ngpios; ++ i ) { struct gpio_device *gpio = &(gpios[i]); 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); gpio->next.external_clock = value; if ( use_external_clock && (gpio->next.external_clock != gpio->curr.external_clock) && (value != negative_edge) ) gpio_device_clock( gpio ); } } /* Clock as handld by one device. */ void gpio_device_clock( struct gpio_device *gpio ) { /* Calculate new inputs and outputs */ gpio->next.in &= ~gpio->next.oe; /* Only input bits */ /* 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.oe; /* Only output-enabled bits */ /* If any outputs changed, notify the world (i.e. vapi) */ if ( gpio->next.out != gpio->curr.out ) { debug( 4, "GPIO: New output 0x%08lx, RGPIO_OE = 0x%08lx\n", gpio->next.out, gpio->next.oe ); if ( gpio->base_vapi_id ) vapi_send( gpio->base_vapi_id + GPIO_VAPI_DATA, gpio->next.out ); } /* If any inputs changed and interrupt enabled, generate interrupt */ if ( gpio->next.in != gpio->curr.in ) { debug( 4, "GPIO: New input 0x%08lx\n", gpio->next.in ); if ( gpio->next.ctrl & RGPIO_CTRL_INTE ) { 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 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); if ( relevant_bits & gpio->next.inte ) { debug( 3, "GPIO: Reporting interrupt %d\n", gpio->irq ); report_interrupt( gpio->irq ); gpio->next.ctrl |= RGPIO_CTRL_INTS; gpio->next.ints |= relevant_bits & gpio->next.inte; } } } /* Switch to values for next clock */ memcpy( &(gpio->curr), &(gpio->next), sizeof(gpio->curr) ); }
Go to most recent revision | Compare with Previous | Blame | View Log