diff options
-rw-r--r-- | 02-usart/include/arch/arm/arch.h | 2 | ||||
-rw-r--r-- | 02-usart/include/arch/x86_64/arch.h | 2 | ||||
-rw-r--r-- | 02-usart/include/core/irq.h | 58 | ||||
-rw-r--r-- | 02-usart/include/core/nvic.h | 46 | ||||
-rw-r--r-- | 02-usart/src/core/irq.c | 15 | ||||
-rw-r--r-- | 02-usart/src/main.c | 4 | ||||
-rw-r--r-- | 02-usart/src/mem.c | 19 | ||||
-rw-r--r-- | 02-usart/test_harness/fake_env.h | 1 | ||||
-rw-r--r-- | 02-usart/test_harness/test_harness.c | 23 | ||||
-rw-r--r-- | 02-usart/test_harness/test_harness.h | 26 | ||||
-rw-r--r-- | 02-usart/tests/test_irq.c | 37 |
11 files changed, 203 insertions, 30 deletions
diff --git a/02-usart/include/arch/arm/arch.h b/02-usart/include/arch/arm/arch.h index a3b93dc..175c984 100644 --- a/02-usart/include/arch/arm/arch.h +++ b/02-usart/include/arch/arm/arch.h @@ -7,7 +7,7 @@ #define CORTEX_M4 -#define enable_interrupts() \ +#define enable_all_interrupts() \ asm volatile(" cpsie i ") diff --git a/02-usart/include/arch/x86_64/arch.h b/02-usart/include/arch/x86_64/arch.h index a39df9a..a93425d 100644 --- a/02-usart/include/arch/x86_64/arch.h +++ b/02-usart/include/arch/x86_64/arch.h @@ -4,7 +4,7 @@ #include "fake_env.h" #define ARCH_PC -#define enable_interrupts() do {} while(0) +#define enable_all_interrupts() do {} while(0) #define DMA1_BASE (load_fake_ahb1__() + 0x0) #define DMA2_BASE (load_fake_ahb1__() + 0x400) diff --git a/02-usart/include/core/irq.h b/02-usart/include/core/irq.h index ae1126d..f2fe8d9 100644 --- a/02-usart/include/core/irq.h +++ b/02-usart/include/core/irq.h @@ -16,6 +16,42 @@ typedef enum { #undef IRQ_RESERVED } interrupt_t; +/* Defines a set of interrupts so they may be enabled all at once. */ +typedef struct { + uint32_t sysirqs; /* System iterrupts. */ + uint32_t irqs[8]; +} interrupt_set_t; + +inline static void interrupt_set_add( + interrupt_set_t* interrupt_set, interrupt_t interrupt) +{ + if (interrupt < 16) { + interrupt_set->sysirqs |= 1 << interrupt; + return; + } + + interrupt -= 16; + int loc = interrupt / 32; + int off = interrupt % 32; + + interrupt_set->irqs[loc] |= 1 << off; +} + +inline static void interrupt_set_remove( + interrupt_set_t* interrupt_set, interrupt_t interrupt) +{ + if (interrupt < 16) { + interrupt_set->sysirqs &= ~(1 << interrupt); + return; + } + + interrupt -= 16; + int loc = interrupt / 32; + int off = interrupt % 32; + + interrupt_set->irqs[loc] &= ~(1 << off); +} + /* * The interrupt service routines. These link in the function `main` as the * main function. @@ -28,6 +64,26 @@ extern const void* vectors[]; */ void unhandled_isr(uint8_t val); -void isr_simple_pin_on(); +#define enable_interrupt(val) \ + {interrupt_set_t itrset = { 0 }; \ + interrupt_set_add(&itrset, val); \ + enable_interrupts(&itrset);} + +#define disable_interrupt(val) \ + {interrupt_set_t itrset = { 0 }; \ + interrupt_set_add(&itrset, val); \ + disable_interrupts(&itrset);} + +/* + * Enables the provided interrupt. Note that if the interrupt is one of the + * system interrupts (first 16) this function has no effect because those + * interrupts are always enabled. + */ +void enable_interrupts(interrupt_set_t* interrupts); + +/* + * Enables the provided interrupt + */ +void disable_interrupts(interrupt_set_t* interrupts); #endif /* CORE_IRQ_H_ */ diff --git a/02-usart/include/core/nvic.h b/02-usart/include/core/nvic.h new file mode 100644 index 0000000..c761574 --- /dev/null +++ b/02-usart/include/core/nvic.h @@ -0,0 +1,46 @@ +#ifndef NVIC_H_ +#define NVIC_H_ + +#include "arch.h" +#include "common.h" + +typedef __IO struct { +#define nvic_intlinesnum (0x0F << 0) + uint32_t ict_r; /* Interrupt control type register. */ + + uint8_t reserved0[0xF8]; + + uint32_t ise_r[8]; + + uint8_t reserved1[0x60]; + + uint32_t ice_r[8]; + + uint8_t reserved2[0x60]; + + uint32_t isp_r[8]; + + uint8_t reserved3[0x60]; + + uint32_t icp_r[8]; + + uint8_t reserved4[0x60]; + + uint32_t iab_r[8]; + + uint8_t reserved5[0xE0]; + + uint32_t ip_r[60]; +} nvic_t; + +static_assert(offsetof(nvic_t, ise_r) == 0x00FC, "Offset check failed"); +static_assert(offsetof(nvic_t, ice_r) == 0x017C, "Offset check failed"); +static_assert(offsetof(nvic_t, isp_r) == 0x01FC, "Offset check failed"); +static_assert(offsetof(nvic_t, icp_r) == 0x027C, "Offset check failed"); +static_assert(offsetof(nvic_t, iab_r) == 0x02FC, "Offset check failed"); +static_assert(offsetof(nvic_t, ip_r) == 0x03FC, "Offset check failed"); + +#define NVIC (* (nvic_t*) NVIC_BASE) + + +#endif /* NVIC_H_ */ diff --git a/02-usart/src/core/irq.c b/02-usart/src/core/irq.c index c9b93c2..47ad924 100644 --- a/02-usart/src/core/irq.c +++ b/02-usart/src/core/irq.c @@ -1,11 +1,10 @@ #include "core/irq.h" #include "core/gpio.h" +#include "core/nvic.h" #include "arch.h" #include "delay.h" -#ifdef ARCH_STM32L4 - #define IRQ_RESERVED(n) #define IRQ(name, uname_, n) \ void WEAK name () { \ @@ -80,4 +79,14 @@ void unhandled_isr(uint8_t number) } } -#endif +void enable_interrupts(interrupt_set_t* interrupts) +{ + for (int i = 0; i < sizeof(NVIC.ise_r) / sizeof(uint32_t); ++ i) + NVIC.ise_r[i] = interrupts->irqs[i]; +} + +void disable_interrupts(interrupt_set_t* interrupts) +{ + for (int i = 0; i < sizeof(NVIC.ise_r) / sizeof(uint32_t); ++ i) + NVIC.ice_r[i] = interrupts->irqs[i]; +} diff --git a/02-usart/src/main.c b/02-usart/src/main.c index 6d22486..8b98cbf 100644 --- a/02-usart/src/main.c +++ b/02-usart/src/main.c @@ -6,6 +6,7 @@ #include "core/system.h" #include "core/usart.h" #include "core/nvic.h" +#include "core/irq.h" #include "delay.h" #include "mem.h" @@ -64,6 +65,9 @@ int main() regset(USART2.c_r1, usart_txeie, 1); regset(USART2.c_r1, usart_rxneie, 1); usart_set_enabled(&USART2, USART_ENABLE_TX | USART_ENABLE_RX); + + + enable_interrupt(IRQ_USART2); USART2.td_r = (uint8_t) 0x61; __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B); diff --git a/02-usart/src/mem.c b/02-usart/src/mem.c index 9fef8bc..65d8b60 100644 --- a/02-usart/src/mem.c +++ b/02-usart/src/mem.c @@ -1,6 +1,25 @@ +#include "arch.h" #include "mem.h" #include "common.h" +#ifdef ARCH_STM32L4 +// Provide a definition for memset() + +void* memset(void* dest, int c, size_t n) +{ + uint8_t c8 = (uint8_t) c; + uint8_t* dest8 = (uint8_t*) dest; + uint8_t* to = dest8 + n; + + while(dest8 < to) { + *(dest8 ++) = c8; + } + + return dest; +} + +#endif + // void memcpy_(void* dest, const void* src, size_t len) // { // uint8_t* dest_ = (uint8_t*) dest; diff --git a/02-usart/test_harness/fake_env.h b/02-usart/test_harness/fake_env.h index 09891bc..3cc6310 100644 --- a/02-usart/test_harness/fake_env.h +++ b/02-usart/test_harness/fake_env.h @@ -10,5 +10,6 @@ void* load_fake_apb2__(); void* load_fake_sram1__(); void* load_fake_sram2__(); void* load_fake_scb__(); +void* load_fake_nvic__(); #endif /* FAKE_ENV_H_ */ diff --git a/02-usart/test_harness/test_harness.c b/02-usart/test_harness/test_harness.c index 9f7dd79..3a6d10a 100644 --- a/02-usart/test_harness/test_harness.c +++ b/02-usart/test_harness/test_harness.c @@ -46,7 +46,6 @@ static int execute_test(test_t* test) int status; int ec; pid_t pid; - const char* note = ""; snprintf( fullname, sizeof(fullname), "%s::%s", iter->test_suite, iter->test_name); @@ -66,17 +65,21 @@ static int execute_test(test_t* test) return 1; } - ec = WEXITSTATUS(status); - switch (ec) { - case 0: - printf("%s " GREEN "[PASS]" RESET "\n", fullname); - return 0; - case 11: - note = " (SIGSEGV)"; - break; + if (WIFEXITED(status)) { + switch ((ec = WEXITSTATUS(status))) { + case 0: + printf("%s " GREEN "[PASS]" RESET "\n", fullname); + return 0; + default: + printf("%s " RED "[FAIL] %d" RESET "\n", fullname, ec); + return ec; + } + } else if (WIFSIGNALED(status)) { + int ec = WTERMSIG(status); + printf("%s " RED "[FAIL] signaled %d" RESET "\n", fullname, ec); + return ec; } - printf("%s " RED "[FAIL] %d%s" RESET "\n", fullname, ec, note); return ec; } } diff --git a/02-usart/test_harness/test_harness.h b/02-usart/test_harness/test_harness.h index 0a218f8..74f3faa 100644 --- a/02-usart/test_harness/test_harness.h +++ b/02-usart/test_harness/test_harness.h @@ -20,20 +20,18 @@ typedef struct { fprintf(stderr, fmt "\n", v1, v2) #define FORMAT_STRING(v1, v2) \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wpointer-to-int-cast\""); \ - _Generic(v1, long: GENPR("%ld == %ld", v1, v2), \ - unsigned long: GENPR("%lu == %lu", v1, v2), \ - int: GENPR("%d == %d", v1, v2), \ - unsigned int: GENPR("%u == %u", v1, v2), \ - short: GENPR("%h == %h", v1, v2), \ - unsigned short: GENPR("%hu == %hu", v1, v2), \ - char: GENPR("%c == %c", v1, v2), \ - double: GENPR("%f == %f", v1, v2), \ - unsigned char: fprintf( \ - stderr, "%02x == %02x\n", (unsigned int) v1, (unsigned int) v2),\ - default: GENPR("%p == %p\n", v1, v2)); \ - _Pragma("GCC diagnostic pop") + fprintf( \ + stderr, \ + _Generic((v1), long: "%ld == %ld\n", \ + unsigned long: "%lu == %lu\n", \ + int: "%d == %d\n", \ + unsigned int: "%u == %u\n", \ + short: "%hu == %hu\n", \ + unsigned short: "%hu == %hu\n", \ + char: "%c == %c\n", \ + double: "%f == %f\n", \ + default: "%p == %p\n"), \ + (v1), (v2)); \ #define TRY_PRINT_TYPE(v1, v2, type, fmt) \ else if (__builtin_types_compatible_p(typeof (v1), type)) { \ diff --git a/02-usart/tests/test_irq.c b/02-usart/tests/test_irq.c new file mode 100644 index 0000000..89eea11 --- /dev/null +++ b/02-usart/tests/test_irq.c @@ -0,0 +1,37 @@ +#include "test_harness.h" + +#include "core/irq.h" +#include "core/nvic.h" + +TEST(irq, nvic) +{ + interrupt_set_t is = { 0 }; + + interrupt_set_add(&is, IRQ_USART2); + interrupt_set_add(&is, IRQ_USART3); + + enable_interrupts(&is); + + ASSERT_EQ(is.irqs[1], 0xC0); + ASSERT_EQ(NVIC.ise_r[1], 0xC0); +} + +TEST(irq, nvic_edgecase) +{ + interrupt_set_t is = { 0 }; + interrupt_set_add(&is, IRQ_WWDG_IRQ); + interrupt_set_add(&is, IRQ_I2C1_ER); + + enable_interrupts(&is); + + ASSERT_EQ(is.irqs[0], 1); + ASSERT_EQ(NVIC.ise_r[0], 1); + ASSERT_EQ(is.irqs[1], 1); + ASSERT_EQ(NVIC.ise_r[1], 1); +} + +TEST(irq, enable_single_interrupt) +{ + enable_interrupt(IRQ_USART2); + ASSERT_EQ(NVIC.ise_r[1], 0x40); +} |