1 // See LICENSE for license details.
\r
5 #include "platform.h"
\r
7 #include "plic/plic_driver.h"
\r
8 #include "encoding.h"
\r
10 #include "stdatomic.h"
\r
12 void reset_demo (void);
\r
14 // Structures for registering different interrupt handlers
\r
15 // for different parts of the application.
\r
16 typedef void (*function_ptr_t) (void);
\r
18 void no_interrupt_handler (void) {};
\r
20 function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS];
\r
23 // Instance data for the PLIC.
\r
25 plic_instance_t g_plic;
\r
28 /*Entry Point for PLIC Interrupt Handler*/
\r
29 void handle_m_ext_interrupt(){
\r
30 plic_source int_num = PLIC_claim_interrupt(&g_plic);
\r
31 if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS)) {
\r
32 g_ext_interrupt_handlers[int_num]();
\r
35 exit(1 + (uintptr_t) int_num);
\r
37 PLIC_complete_interrupt(&g_plic, int_num);
\r
41 /*Entry Point for Machine Timer Interrupt Handler*/
\r
42 void handle_m_time_interrupt(){
\r
44 clear_csr(mie, MIP_MTIP);
\r
46 // Reset the timer for 3s in the future.
\r
47 // This also clears the existing timer interrupt.
\r
49 volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
\r
50 volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
\r
51 uint64_t now = *mtime;
\r
52 uint64_t then = now + 2 * RTC_FREQ;
\r
55 // read the current value of the LEDS and invert them.
\r
56 uint32_t leds = GPIO_REG(GPIO_OUTPUT_VAL);
\r
58 GPIO_REG(GPIO_OUTPUT_VAL) ^= ((0x1 << RED_LED_OFFSET) |
\r
59 (0x1 << GREEN_LED_OFFSET) |
\r
60 (0x1 << BLUE_LED_OFFSET));
\r
62 // Re-enable the timer interrupt.
\r
63 set_csr(mie, MIP_MTIP);
\r
68 const char * instructions_msg = " \
\r
72 5555555555555555555555555\n\
\r
76 5555 5555555555555555555555\n\
\r
77 5555 555555555555555555555555\n\
\r
81 5555555555555555555555555555 55555\n\
\r
82 55555 555555555 55555\n\
\r
83 55555 55555 55555\n\
\r
94 SiFive E-Series Software Development Kit 'demo_gpio' program.\n\
\r
95 Every 2 second, the Timer Interrupt will invert the LEDs.\n\
\r
96 (Arty Dev Kit Only): Press Buttons 0, 1, 2 to Set the LEDs.\n\
\r
97 Pin 19 (HiFive1) or A5 (Arty Dev Kit) is being bit-banged\n\
\r
98 for GPIO speed demonstration.\n\
\r
102 void print_instructions() {
\r
104 write (STDOUT_FILENO, instructions_msg, strlen(instructions_msg));
\r
108 #ifdef HAS_BOARD_BUTTONS
\r
109 void button_0_handler(void) {
\r
112 GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << RED_LED_OFFSET);
\r
114 // Clear the GPIO Pending interrupt by writing 1.
\r
115 GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_0_OFFSET);
\r
119 void button_1_handler(void) {
\r
122 GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << GREEN_LED_OFFSET);
\r
124 // Clear the GPIO Pending interrupt by writing 1.
\r
125 GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_1_OFFSET);
\r
130 void button_2_handler(void) {
\r
133 GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << BLUE_LED_OFFSET);
\r
135 GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_2_OFFSET);
\r
140 void reset_demo (){
\r
142 // Disable the machine & timer interrupts until setup is done.
\r
144 clear_csr(mie, MIP_MEIP);
\r
145 clear_csr(mie, MIP_MTIP);
\r
147 for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++){
\r
148 g_ext_interrupt_handlers[ii] = no_interrupt_handler;
\r
151 #ifdef HAS_BOARD_BUTTONS
\r
152 g_ext_interrupt_handlers[INT_DEVICE_BUTTON_0] = button_0_handler;
\r
153 g_ext_interrupt_handlers[INT_DEVICE_BUTTON_1] = button_1_handler;
\r
154 g_ext_interrupt_handlers[INT_DEVICE_BUTTON_2] = button_2_handler;
\r
157 print_instructions();
\r
159 #ifdef HAS_BOARD_BUTTONS
\r
161 // Have to enable the interrupt both at the GPIO level,
\r
162 // and at the PLIC level.
\r
163 PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_0);
\r
164 PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_1);
\r
165 PLIC_enable_interrupt (&g_plic, INT_DEVICE_BUTTON_2);
\r
167 // Priority must be set > 0 to trigger the interrupt.
\r
168 PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_0, 1);
\r
169 PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_1, 1);
\r
170 PLIC_set_priority(&g_plic, INT_DEVICE_BUTTON_2, 1);
\r
172 GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_0_OFFSET);
\r
173 GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_1_OFFSET);
\r
174 GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_2_OFFSET);
\r
178 // Set the machine timer to go off in 3 seconds.
\r
180 volatile uint64_t * mtime = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
\r
181 volatile uint64_t * mtimecmp = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
\r
182 uint64_t now = *mtime;
\r
183 uint64_t then = now + 2*RTC_FREQ;
\r
186 // Enable the Machine-External bit in MIE
\r
187 set_csr(mie, MIP_MEIP);
\r
189 // Enable the Machine-Timer bit in MIE
\r
190 set_csr(mie, MIP_MTIP);
\r
192 // Enable interrupts in general.
\r
193 set_csr(mstatus, MSTATUS_MIE);
\r
196 int main(int argc, char **argv)
\r
198 // Set up the GPIOs such that the LED GPIO
\r
199 // can be used as both Inputs and Outputs.
\r
202 #ifdef HAS_BOARD_BUTTONS
\r
203 GPIO_REG(GPIO_OUTPUT_EN) &= ~((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x1 << BUTTON_2_OFFSET));
\r
204 GPIO_REG(GPIO_PULLUP_EN) &= ~((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x1 << BUTTON_2_OFFSET));
\r
205 GPIO_REG(GPIO_INPUT_EN) |= ((0x1 << BUTTON_0_OFFSET) | (0x1 << BUTTON_1_OFFSET) | (0x1 << BUTTON_2_OFFSET));
\r
208 GPIO_REG(GPIO_INPUT_EN) &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ;
\r
209 GPIO_REG(GPIO_OUTPUT_EN) |= ((0x1<< RED_LED_OFFSET)| (0x1<< GREEN_LED_OFFSET) | (0x1 << BLUE_LED_OFFSET)) ;
\r
210 GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << BLUE_LED_OFFSET) ;
\r
211 GPIO_REG(GPIO_OUTPUT_VAL) &= ~((0x1<< RED_LED_OFFSET) | (0x1<< GREEN_LED_OFFSET)) ;
\r
214 // For Bit-banging with Atomics demo.
\r
216 uint32_t bitbang_mask = 0;
\r
217 #ifdef _SIFIVE_HIFIVE1_H
\r
218 bitbang_mask = (1 << PIN_19_OFFSET);
\r
220 #ifdef _SIFIVE_COREPLEXIP_ARTY_H
\r
221 bitbang_mask = (0x1 << JA_0_OFFSET);
\r
225 GPIO_REG(GPIO_OUTPUT_EN) |= bitbang_mask;
\r
227 /**************************************************************************
\r
230 *************************************************************************/
\r
233 PLIC_NUM_INTERRUPTS,
\r
234 PLIC_NUM_PRIORITIES);
\r
238 /**************************************************************************
\r
239 * Demonstrate fast GPIO bit-banging.
\r
240 * One can bang it faster than this if you know
\r
241 * the entire OUTPUT_VAL that you want to write, but
\r
242 * Atomics give a quick way to control a single bit.
\r
243 *************************************************************************/
\r
244 // For Bit-banging with Atomics demo.
\r
247 atomic_fetch_xor_explicit(&GPIO_REG(GPIO_OUTPUT_VAL), bitbang_mask, memory_order_relaxed);
\r
255 void trap_entry( void )
\r
257 #warning Dummy until kernel code is incldued.
\r