Proper interrupt handlers

Proper interrupt handlers for timers (and new peripherals can use them
too).
Improved interrupt enabling.
Improved timer interrupts and fixed minor bugs.
This commit is contained in:
giomba 2019-01-07 15:57:16 +01:00
parent 06f000e19a
commit 92e1e261e7
8 changed files with 53 additions and 36 deletions

View File

@ -39,6 +39,7 @@ namespace GIC {
};
void enable(void);
void enableInterrupt(const uint16_t m, const TargetCPU target, const Sensitivity sensitivity);
}
#endif

View File

@ -3,10 +3,10 @@
#include <stdint.h>
extern "C" void setVectorBAR(void);
extern "C" address_t* getVectorBAR(void);
extern "C" void fireswi(void);
namespace interrupt {
extern void (*handler[])(const uint8_t cpuID, const uint16_t interruptID);
}
#endif

View File

@ -43,8 +43,9 @@ namespace Timer {
class Timer {
private:
uint8_t n;
TimerModule* module;
uint8_t n; /* Timer module number (0-5) */
uint16_t src; /* Timer interrupt source line (54-57, 99-100) */
TimerModule* module; /* Timer module MMIO config registers */
public:
/* Initialize class instance as timer n
* where n is found on Allwinner datasheet */
@ -57,6 +58,9 @@ namespace Timer {
void stop(void);
};
/* Interrupt handler */
extern void handler(const uint8_t cpuID, const uint16_t interruptID);
/* Vector of system's timers */
extern Timer timer[];

View File

@ -27,25 +27,9 @@ namespace GIC {
cpuInterface[1] = 0xff;
}
void printDistributorStatus(void) {
for (short i = 0; i < 1024; ++i) {
printk("Distributor "); printk(itoa(i * 4)); printk(" : ");
printkl(itoa(distributor[i]));
}
}
void printCPUInterfaceStatus(void) {
for (short i = 0; i < 64; ++i) {
printk("CPUInterface "); printk(itoa(i * 4)); printk(" : ");
printkl(itoa(cpuInterface[i]));
}
}
void enable(void) {
enableInterrupt(54, CPU0T, EDGE); /* Timer0 */
/* Enable distributor and CPU interfaces
* Do this always at the end,
* Call this function always at the end,
* since writing on GIC registers is not allowed when it is enabled */
distributor[0] = distributor[GICD_CTLR] | 0x1;
cpuInterface[0] = cpuInterface[GICC_CTLR] | 0x1;

6
src/interrupt.cpp Normal file
View File

@ -0,0 +1,6 @@
#include <stdint.h>
namespace interrupt {
void (*handler[128])(const uint8_t cpuID, const uint16_t interruptID);
}

View File

@ -15,12 +15,14 @@ extern "C" int main(int argc, char** argv) {
printkl("Now firing test software interrupt...");
fireswi();
printkl("Now enabling GIC interrupts...");
GIC::enable();
printkl("Now enabling timer...");
Timer::timer[0].set(0x80, Timer::CONTINUOUS, Timer::PRESCALER_128, Timer::LS_OSC);
Timer::timer[0].set(0x100, Timer::CONTINUOUS, Timer::PRESCALER_128, Timer::LS_OSC);
Timer::timer[0].start();
Timer::timer[5].set(0x100, Timer::CONTINUOUS, Timer::PRESCALER_16, Timer::LS_OSC);
Timer::timer[5].start();
printkl("Now enabling GIC...");
GIC::enable();
printkl("Now going user...");
go_usr();

View File

@ -1,16 +1,23 @@
#include <gic.h>
#include <interrupt.h>
#include <timer.h>
#include <dbg.h>
namespace Timer {
Timer timer[3] = { Timer(0), Timer(1), Timer(2) };
Timer timer[6] = { Timer(0), Timer(1), Timer(2), Timer(3), Timer(4), Timer(5) };
Timer::Timer(uint8_t n) {
this->n = n;
module = (TimerModule*)(TMR_MODULE_BASE + n);
if (n >= 0 && n <= 3) this->src = 54 + n;
if (n >= 4 && n <= 5) this->src = 99 - 4 + n;
module = (TimerModule*)(TMR_MODULE_BASE + n * 4);
}
void Timer::set(uint32_t interval, Mode mode, Prescaler prescaler, ClockSource source) {
/* attach interrupt handler */
interrupt::handler[src] = handler;
/* zero fill control registers */
module->TMR_CTLR_REG = 0;
module->TMR_CUR_VALUE_REG = 0;
@ -21,9 +28,9 @@ namespace Timer {
/* Set timer value */
module->TMR_INTV_VALUE_REG = interval;
/* Enable interrupt */
/* Enable interrupt in GIC and set interrupt handler */
GIC::enableInterrupt(src, GIC::CPU0T, GIC::EDGE);
peripheral->TMR_IRQ_EN_REG = peripheral->TMR_IRQ_EN_REG | (1 << n);
}
void Timer::start(void) {
@ -36,4 +43,12 @@ namespace Timer {
module->TMR_CTLR_REG = module->TMR_CTLR_REG & 0xfffffffe;
}
void handler(const uint8_t cpuID, const uint16_t interruptID) {
uint16_t n;
if (interruptID >= 54 && interruptID <= 57) n = interruptID - 54;
if (interruptID >= 99 && interruptID <= 100) n = interruptID - 99 + 4;
peripheral->TMR_IRQ_STA_REG = peripheral->TMR_IRQ_STA_REG | (1 << n);
}
}

View File

@ -1,23 +1,28 @@
#include <dbg.h>
#include <interrupt.h>
#include <stdint.h>
extern "C" uint32_t c_irq_handler(uint32_t iar) {
uint8_t cpuID = (iar >> 10) & 0x7;
uint16_t interruptID = iar & 0x3ff;
printk("Serving IRQ #"); printkl(itoa(interruptID));
void (*handler)(const uint8_t, const uint16_t);
if (cpuID == 0) {
/* for
* SPI - Shared Peripheral Interrupt
* PPI - Private Peripheral Interrupt
*/
switch (interruptID) {
case 54: /* timer 0 */ /* TODO: improve this ugliness */
uint32_t* const TMR_IRQ_STA_REG = (uint32_t* const)(0x01c20c04);
*TMR_IRQ_STA_REG = *TMR_IRQ_STA_REG | 0x1;
printk("Serving IRQ #");
printkl(itoa(interruptID));
switch (interruptID) { /* Choose proper interrupt handler */
case 54: case 55: case 56: case 57: case 99: case 100:
handler = interrupt::handler[interruptID];
break;
}
/* Call interrupt handler */
handler(cpuID, interruptID);
}
else {
/* for