From d6d04862de9126d0930ae1f4b95ff6077c6eda63 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Wed, 4 Dec 2024 00:20:36 -0700 Subject: Basic interrupts are working. --- fdl/ch573/pfic.fdl | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ fdl/ch573/systick.fdl | 72 +++++++++++++++++++++++++++++++++ include/isr_vector.h | 16 ++++++++ include/systick.h | 9 +++++ src/init.c | 6 +++ src/main.c | 19 ++++++++- src/systick.c | 34 ++++++++++++++++ 7 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 fdl/ch573/pfic.fdl create mode 100644 fdl/ch573/systick.fdl create mode 100644 include/systick.h create mode 100644 src/systick.c diff --git a/fdl/ch573/pfic.fdl b/fdl/ch573/pfic.fdl new file mode 100644 index 0000000..13ed54f --- /dev/null +++ b/fdl/ch573/pfic.fdl @@ -0,0 +1,109 @@ +import "ch573/common.fdl"; + +/** Fiddle file for the Programmable Fast Interrupt Controller (PFIC) */ +package ch573.pfic { + location pfic_base = 0xE000E000; + + using ch573.common; + + bits interrupts : enum(32) { + [[ c: unqualified ]] + IRQ_SysTick = 0x1000, + }; + + /** Type definition for the PFIC structure */ + type pfic_t : struct { + /** PFIC interrupt enable status register */ + reg interrupt_enable_status(64) @0x00 : struct { + intensta_low : (32); // Interrupt enable status for interrupts 31:0 + intensta_high : (32); // Interrupt enable status for interrupts 63:32 + }; + + /** PFIC interrupt suspension status register */ + reg interrupt_suspension_status(64) @0x20 : struct { + pendsta_low : (32); // Interrupt suspension status for interrupts 31:0 + pendsta_high : (32); // Interrupt suspension status for interrupts 63:32 + }; + + /** PFIC interrupt priority threshold configuration register */ + reg interrupt_priority_threshold(32) @0x40 : struct { + threshold : (8); // Priority threshold setting + reserved(24); + }; + + /** PFIC fast interrupt service base address registers */ + reg fast_interrupt_base_address(64) : struct { + irqid0 : (8); // IRQ ID for fast interrupt 0 + offset0 : (24); // Offset address for fast interrupt 0 + irqid1 : (8); // IRQ ID for fast interrupt 1 + offset1 : (24); // Offset address for fast interrupt 1 + }; + + reg fast_interrupt_base_address_2(64) : struct { + irqid2 : (8); // IRQ ID for fast interrupt 2 + offset2 : (24); // Offset address for fast interrupt 2 + irqid3 : (8); // IRQ ID for fast interrupt 3 + offset3 : (24); // Offset address for fast interrupt 3 + }; + + /** PFIC interrupt enable register */ + reg interrupt_enable(64) @0x100 : struct { + enable_low : (32); // Enable for interrupts 31:0 + enable_high : (32); // Enable for interrupts 63:32 + }; + + /** PFIC interrupt disable register */ + reg interrupt_disable(64) : struct { + disable_low : (32); // Disable for interrupts 31:0 + disable_high : (32); // Disable for interrupts 63:32 + }; + + /** PFIC interrupt pending set register */ + reg interrupt_pending_set(64) : struct { + pendset_low : (32); // Pending set for interrupts 31:0 + pendset_high : (32); // Pending set for interrupts 63:32 + }; + + /** PFIC interrupt pending clear register */ + reg interrupt_pending_clear(64) : struct { + pendreset_low : (32); // Pending clear for interrupts 31:0 + pendreset_high : (32); // Pending clear for interrupts 63:32 + }; + + /** PFIC interrupt activation status register */ + reg interrupt_active_status(64) : struct { + active_low : (32); // Active status for interrupts 31:0 + active_high : (32); // Active status for interrupts 63:32 + }; + + /** PFIC interrupt priority configuration registers (IPRIORx) */ + reg interrupt_priority_config(64) : struct { + priority_0_to_3 : (8); // Priority for interrupts 0-3 + priority_4_to_7 : (8); // Priority for interrupts 4-7 + priority_8_to_11 : (8); // Priority for interrupts 8-11 + priority_12_to_15 : (8); // Priority for interrupts 12-15 + priority_16_to_19 : (8); // Priority for interrupts 16-19 + priority_20_to_23 : (8); // Priority for interrupts 20-23 + priority_24_to_27 : (8); // Priority for interrupts 24-27 + priority_28_to_31 : (8); // Priority for interrupts 28-31 + }; + + /** PFIC system control register */ + reg system_control(32) : struct { + hwstkctrl : bit_t; // Hardware stack enable control + nestctrl : bit_t; // Nesting interrupt control + sleepdeep : bit_t; // Low power consumption control + reserved(29); + }; + + /** PFIC vector table control register */ + reg vector_table_control(32) : struct { + offset : bit_t; // Offset vector table address + reserved(31); + }; + }; + + /** Define an instance of the PFIC at the base address */ + instance pfic at pfic_base : pfic_t; +}; + diff --git a/fdl/ch573/systick.fdl b/fdl/ch573/systick.fdl new file mode 100644 index 0000000..8e05685 --- /dev/null +++ b/fdl/ch573/systick.fdl @@ -0,0 +1,72 @@ +import "ch573/common.fdl"; + +/** Package for SYSTICK (system counter). */ +package ch573.systick { + location systick_base = 0xE000F000; + + using ch573.common; + + type systick_t : struct { + reg cfg(32) @0x0 : struct { + /** Enable the systick. */ + rw enabled : enable_t; + + /** Enable the systick interrupt. */ + rw interrupt_enable : enable_t; + + /** Clock source for the systick. */ + rw clock_source : enum(1) { + [[ c: unqualified ]] + SYSTICK_CLOCK_SOURCE_HCLK = 1, + + [[ c: unqualified ]] + SYSTICK_CLOCK_SOURCE_HCLK_DIV_8 = 0, + }; + + reserved(5); + + /** Write 1 to reload the systick. */ + wo st_reload : (1); + reserved(23); + }; + + assert_pos(0x4); + union { + struct { + /** Lower 32 bits of the systick count. */ + reg count_low(32); + assert_pos(0x8); + + /** Upper 32 bits of the systick count. */ + reg count_high(32); + }; + /** Full 64 bits of the systick count. */ + reg count(64); + }; + + assert_pos(0xC); + union { + struct { + /** Lower 32 bits of the systick reload value. */ + reg reload_low(32); + assert_pos(0x10); + /** Upper 32 bits of the systick reload value. */ + reg reload_high(32); + }; + /** Full 64-bit systick reload value. */ + reg reload(64); + }; + + reg (32) @0x14 : struct { + /** Software interrupt happened. (Set to 1 to trigger a software + * interrupt.) */ + software_interrupt_flag : (1); + + /** Counter interrupt happened. */ + counter_interrupt_flag : (1); + reserved(30); + }; + }; + + instance systick at systick_base : systick_t; +}; diff --git a/include/isr_vector.h b/include/isr_vector.h index 6059875..3d4070a 100644 --- a/include/isr_vector.h +++ b/include/isr_vector.h @@ -51,3 +51,19 @@ void irq_on_wdog_bat(void); _real__irq_on_##name(); \ } \ static void __attribute__((noinline)) _real__irq_on_##name(void) + +inline static void enable_interrupts() +{ + int mstatus; + asm volatile ("csrr %0, mstatus" : "=r"(mstatus)); + mstatus |= 0x88; + asm volatile ("csrw mstatus, %0" : : "r"(mstatus)); +} + +inline static void disable_interrupts() +{ + int mstatus; + asm volatile ("csrr %0, mstatus" : "=r"(mstatus)); + mstatus &= ~0x88; + asm volatile ("csrw mstatus, %0" : : "r"(mstatus)); +} diff --git a/include/systick.h b/include/systick.h new file mode 100644 index 0000000..8933a31 --- /dev/null +++ b/include/systick.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +void set_systick(uint64_t systick_value); + +uint64_t get_systick(); + +int systick_interrupt(); diff --git a/src/init.c b/src/init.c index 5a0a7c3..3aacc66 100644 --- a/src/init.c +++ b/src/init.c @@ -1,12 +1,17 @@ #include #include +#include +#include "ch573/systick.h" #include "clock.h" #include "io.h" #include "isr_vector.h" void on_reset(void); +#define SYSTICK_I CH573_SYSTICK__SYSTICK_T_INTF +#define SYSTICK ch573_systick__systick + void __attribute__((weak, interrupt, __section__(".isr_vector.routines"))) default_irq_handler(void) { @@ -111,6 +116,7 @@ static __attribute((__section__(".sinit.1"))) void start(void) init_data_segments(); /* Set the mtvec to the isr_vector. */ set_mtvec(&isr_vector); + enable_interrupts(); /* Initialize stdout. */ init_uart1_for_stdout(); diff --git a/src/main.c b/src/main.c index 2bbd0b3..9f5808b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,10 @@ #include #include #include -#include "string.h" #include "byte_math.h" #include "ch573/gpio.h" +#include "ch573/pfic.h" #include "ch573/pwr.h" #include "ch573/uart.h" #include "clock.h" @@ -13,8 +13,12 @@ #include "string.h" #include "sysled.h" #include "system.h" +#include "systick.h" #include "ws2812b.h" +#define PFIC_I CH573_PFIC__PFIC_T_INTF +#define PFIC ch573_pfic__pfic + #define GPIO_PORT_A ch573_gpio__gpio_port_a #define GPIO_PORT_B ch573_gpio__gpio_port_b #define GPIO_PORT CH573_GPIO__GPIO_PORT_T_INTF @@ -203,14 +207,25 @@ int main(void) { char buf[N_LEDS * TOTAL_BYTES_PER_LED]; + PFIC_I.vector_table_control.set(PFIC, 1); + PFIC->interrupt_priority_threshold = 0x10; + PFIC->interrupt_enable |= IRQ_SysTick; + + printf( + "PFIC enable status 1: %08x\n", + (uint32_t)(PFIC->interrupt_enable_status)); + set_system_clock_60Mhz(); + + set_systick(250000); + enable_sysled(); enable_spi(); size_t n = sizeof(buf); struct ws2812b_buf ws_buf; make_wsb2812b(&ws_buf, buf, n); - ws_buf.byte_order = BYTE_ORDER_RGB; + ws_buf.byte_order = BYTE_ORDER_GRB; rgb_t color; uint32_t time = 0; diff --git a/src/systick.c b/src/systick.c new file mode 100644 index 0000000..506f6df --- /dev/null +++ b/src/systick.c @@ -0,0 +1,34 @@ +#include "systick.h" + +#include + +#include "ch573/systick.h" +#include "isr_vector.h" + +#define SYSTICK_I CH573_SYSTICK__SYSTICK_T_INTF +#define SYSTICK ch573_systick__systick + +void set_systick(uint64_t systick) +{ + SYSTICK_I.reload.set(SYSTICK, systick); + SYSTICK_I.cfg.st_reload.set(SYSTICK, 1); + SYSTICK_I.cfg.interrupt_enable.set(SYSTICK, 1); + + SYSTICK_I.cfg.enabled.set(SYSTICK, ENABLED); +} + +uint64_t get_systick() +{ + return ((uint64_t)SYSTICK_I.count_high.get(SYSTICK) << 32) | + SYSTICK_I.count_low.get(SYSTICK); +} + +int systick_interrupt() +{ + return SYSTICK_I.counter_interrupt_flag.get(SYSTICK); +} + +IRQ(systick) +{ + SYSTICK_I.counter_interrupt_flag.set(SYSTICK, 0); +} -- cgit