diff options
Diffstat (limited to 'software/demo_gpio')
-rw-r--r-- | software/demo_gpio/Makefile | 14 | ||||
-rw-r--r-- | software/demo_gpio/demo_gpio.c | 115 | ||||
-rw-r--r-- | software/demo_gpio/plic_driver.c | 127 |
3 files changed, 195 insertions, 61 deletions
diff --git a/software/demo_gpio/Makefile b/software/demo_gpio/Makefile index 5f201a2..0a0b148 100644 --- a/software/demo_gpio/Makefile +++ b/software/demo_gpio/Makefile @@ -1,9 +1,7 @@ -#See LICENSE for license details. +TARGET = demo_gpio +C_SRCS += demo_gpio.c +C_SRCS += plic_driver.c +CFLAGS += -fno-builtin-printf -DUSE_PLIC -DUSE_M_TIME -TARGET=demo_gpio -CFLAGS += -g -CDEFINES += -DUSE_PLIC -DUSE_M_TIME - -SWDIR = ../ - -include $(SWDIR)/shared/Makefile.shared +BSP_BASE = ../../bsp +include $(BSP_BASE)/env/common.mk diff --git a/software/demo_gpio/demo_gpio.c b/software/demo_gpio/demo_gpio.c index 3b0b6f5..c977281 100644 --- a/software/demo_gpio/demo_gpio.c +++ b/software/demo_gpio/demo_gpio.c @@ -1,10 +1,14 @@ // See LICENSE for license details. #include <stdio.h> - -#include "shared.h" -#include "plic.h" +#include <stdlib.h> +#include "platform.h" #include <string.h> +#include "plic_driver.h" +#include "encoding.h" +#include <unistd.h> + +#define RTC_FREQUENCY 32768 void reset_demo (void); @@ -14,19 +18,19 @@ typedef void (*function_ptr_t) (void); void no_interrupt_handler (void) {}; -function_ptr_t g_ext_interrupt_handlers[9]; +function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS]; -function_ptr_t g_m_timer_interrupt_handler = no_interrupt_handler; // Instance data for the PLIC. plic_instance_t g_plic; // Simple variables for LEDs, buttons, etc. -volatile unsigned int* g_outputs = (unsigned int *) (GPIO_BASE_ADDR + GPIO_OUT_OFFSET); -volatile unsigned int* g_inputs = (unsigned int *) (GPIO_BASE_ADDR + GPIO_IN_OFFSET); -volatile unsigned int* g_tristates = (unsigned int *) (GPIO_BASE_ADDR + GPIO_TRI_OFFSET); - +volatile unsigned int* g_output_vals = (unsigned int *) (GPIO_BASE_ADDR + GPIO_OUTPUT_VAL); +volatile unsigned int* g_input_vals = (unsigned int *) (GPIO_BASE_ADDR + GPIO_INPUT_VAL); +volatile unsigned int* g_output_en = (unsigned int *) (GPIO_BASE_ADDR + GPIO_OUTPUT_EN); +volatile unsigned int* g_pullup_en = (unsigned int *) (GPIO_BASE_ADDR + GPIO_PULLUP_EN); +volatile unsigned int* g_input_en = (unsigned int *) (GPIO_BASE_ADDR + GPIO_INPUT_EN); /*Entry Point for PLIC Interrupt Handler*/ void handle_m_ext_interrupt(){ @@ -35,7 +39,7 @@ void handle_m_ext_interrupt(){ g_ext_interrupt_handlers[int_num](); } else { - _exit(1 + (uintptr_t) int_num); + exit(1 + (uintptr_t) int_num); } PLIC_complete_interrupt(&g_plic, int_num); } @@ -49,31 +53,25 @@ void handle_m_time_interrupt(){ // Reset the timer for 3s in the future. // This also clears the existing timer interrupt. - volatile uint64_t * mtime = (uint64_t*) MTIME_ADDR; - volatile uint64_t * mtimecmp = (uint64_t*) MTIMECMP_BASE_ADDR; + volatile uint64_t * mtime = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME); + volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIMECMP); uint64_t now = *mtime; - uint64_t then = now + 3 * CLOCK_FREQUENCY / RTC_PRESCALER; + uint64_t then = now + 3 * RTC_FREQUENCY; *mtimecmp = then; // read the current value of the LEDS and invert them. - uint32_t leds = *g_outputs; - - *g_outputs = (~leds) & ((0xF << RED_LEDS_OFFSET) | - (0xF << GREEN_LEDS_OFFSET) | - (0xF << BLUE_LEDS_OFFSET)); + uint32_t leds = *g_output_vals; + + *g_output_vals ^= ((0x1 << RED_LED_OFFSET) | + (0x1 << GREEN_LED_OFFSET) | + (0x1 << BLUE_LED_OFFSET)); - // Re-enable the timer interrupt. set_csr(mie, MIP_MTIP); - + } -/*Entry Point for Machine Timer Interrupt Handler*/ -void handle_m_timer_interrupt(){ - g_m_timer_interrupt_handler(); -} - const char * instructions_msg = " \ \n\ SIFIVE, INC.\n\ @@ -112,8 +110,10 @@ void print_instructions() { void button_0_handler(void) { - // Rainbow LEDs! - * g_outputs = (0x9 << RED_LEDS_OFFSET) | (0xA << GREEN_LEDS_OFFSET) | (0xC << BLUE_LEDS_OFFSET); + // All LEDS on + * g_output_vals = (0x1 << RED_LED_OFFSET) | + (0x1 << GREEN_LED_OFFSET) | + (0x1 << BLUE_LED_OFFSET); }; @@ -122,30 +122,31 @@ void reset_demo (){ // Disable the machine & timer interrupts until setup is done. - clear_csr(mie, MIP_MEIP); - clear_csr(mie, MIP_MTIP); + clear_csr(mie, MIP_MEIP); + clear_csr(mie, MIP_MTIP); + + for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++){ + g_ext_interrupt_handlers[ii] = no_interrupt_handler; + } + +#ifdef HAS_BOARD_BUTTONS + g_ext_interrupt_handlers[INT_DEVICE_BUTTON_0] = button_0_handler; +#endif - g_ext_interrupt_handlers[INT_DEVICE_BUTTON_0] = button_0_handler; - g_ext_interrupt_handlers[INT_DEVICE_BUTTON_1] = no_interrupt_handler; - g_ext_interrupt_handlers[INT_DEVICE_BUTTON_2] = no_interrupt_handler; - g_ext_interrupt_handlers[INT_DEVICE_BUTTON_3] = no_interrupt_handler; - g_ext_interrupt_handlers[INT_DEVICE_JA_7] = no_interrupt_handler; - g_ext_interrupt_handlers[INT_DEVICE_JA_8] = no_interrupt_handler; - g_ext_interrupt_handlers[INT_DEVICE_JA_9] = no_interrupt_handler; - g_ext_interrupt_handlers[INT_DEVICE_JA_10] = no_interrupt_handler; - - print_instructions(); + print_instructions(); - PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_0); - +#ifdef HAS_BOARD_BUTTONS + PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_0); +#endif + // Set the machine timer to go off in 3 seconds. // The - volatile uint64_t * mtime = (uint64_t*) MTIME_ADDR; - volatile uint64_t * mtimecmp = (uint64_t*) MTIMECMP_BASE_ADDR; + volatile uint64_t * mtime = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME); + volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIMECMP); uint64_t now = *mtime; - uint64_t then = now + 3*CLOCK_FREQUENCY / RTC_PRESCALER; + uint64_t then = now + 3*RTC_FREQUENCY; *mtimecmp = then; - + // Enable the Machine-External bit in MIE set_csr(mie, MIP_MEIP); @@ -154,24 +155,32 @@ void reset_demo (){ // Enable interrupts in general. set_csr(mstatus, MSTATUS_MIE); - } int main(int argc, char **argv) { - // Set up the GPIOs such that the inputs' tristate are set. - // The boot ROM actually does this, but still good. + // Set up the GPIOs such that the LED GPIO + // can be used as both Inputs and Outputs. + +#ifdef HAS_BOARD_BUTTONS + * g_output_en &= ~((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x2 << BUTTON_2_OFFSET)); + * g_pullup_en &= ~((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x2 << BUTTON_2_OFFSET)); + * g_input_en |= ((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x2 << BUTTON_2_OFFSET)); +#endif - * g_tristates = (0xF << BUTTONS_OFFSET) | (0xF << SWITCHES_OFFSET) | (0xF << JA_IN_OFFSET); - - * g_outputs = (0xF << RED_LEDS_OFFSET); - + * g_input_en &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ; + * g_output_en |= ((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ; + * g_output_vals|= (0x1 << BLUE_LED_OFFSET) ; + * g_output_vals &= ~((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET)) ; /************************************************************************** * Set up the PLIC * *************************************************************************/ - PLIC_init(&g_plic, PLIC_BASE_ADDR, PLIC_NUM_SOURCES, PLIC_NUM_PRIORITIES); + PLIC_init(&g_plic, + PLIC_BASE_ADDR, + PLIC_NUM_INTERRUPTS, + PLIC_NUM_PRIORITIES); reset_demo(); diff --git a/software/demo_gpio/plic_driver.c b/software/demo_gpio/plic_driver.c new file mode 100644 index 0000000..01b7e6e --- /dev/null +++ b/software/demo_gpio/plic_driver.c @@ -0,0 +1,127 @@ +// See LICENSE for license details. + +#include "sifive/devices/plic.h" +#include "plic_driver.h" +#include "platform.h" +#include "encoding.h" +#include <string.h> + + +// Note that there are no assertions or bounds checking on these +// parameter values. + +void volatile_memzero(uint8_t * base, unsigned int size) +{ + volatile uint8_t * ptr; + for (ptr = base; ptr < (base + size); ptr++){ + *ptr = 0; + } +} + +void PLIC_init ( + plic_instance_t * this_plic, + uintptr_t base_addr, + uint32_t num_sources, + uint32_t num_priorities + ) +{ + + this_plic->base_addr = base_addr; + this_plic->num_sources = num_sources; + this_plic->num_priorities = num_priorities; + + // Disable all interrupts (don't assume that these registers are reset). + unsigned long hart_id = read_csr(mhartid); + volatile_memzero((uint8_t*) (this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)), + (num_sources + 8) / 8); + + // Set all priorities to 0 (equal priority -- don't assume that these are reset). + volatile_memzero ((uint8_t *)(this_plic->base_addr + + PLIC_PRIORITY_OFFSET), + (num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE); + + // Set the threshold to 0. + volatile plic_threshold* threshold = (plic_threshold*) + (this_plic->base_addr + + PLIC_THRESHOLD_OFFSET + + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); + + *threshold = 0; + +} + +void PLIC_set_threshold (plic_instance_t * this_plic, + plic_threshold threshold){ + + unsigned long hart_id = read_csr(mhartid); + volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr + + PLIC_THRESHOLD_OFFSET + + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); + + *threshold_ptr = threshold; + +} + + +void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile uint8_t * current_ptr = (volatile uint8_t *)(this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + + (source >> 3)); + uint8_t current = *current_ptr; + current = current | ( 1 << (source & 0x7)); + *current_ptr = current; + +} + +void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile uint8_t * current_ptr = (volatile uint8_t *) (this_plic->base_addr + + PLIC_ENABLE_OFFSET + + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) + + (source >> 3)); + uint8_t current = *current_ptr; + current = current & ~(( 1 << (source & 0x7))); + *current_ptr = current; + +} + +void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority){ + + if (this_plic->num_priorities > 0) { + volatile plic_priority * priority_ptr = (volatile plic_priority *) + (this_plic->base_addr + + PLIC_PRIORITY_OFFSET + + (source << PLIC_PRIORITY_SHIFT_PER_SOURCE)); + *priority_ptr = priority; + } +} + +plic_source PLIC_claim_interrupt(plic_instance_t * this_plic){ + + unsigned long hart_id = read_csr(mhartid); + + volatile plic_source * claim_addr = (volatile plic_source * ) + (this_plic->base_addr + + PLIC_CLAIM_OFFSET + + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); + + return *claim_addr; + +} + +void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source){ + + unsigned long hart_id = read_csr(mhartid); + volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr + + PLIC_CLAIM_OFFSET + + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); + *claim_addr = source; + +} + |