mbv: now with functioning timer interrupts!
And a few other nice things. The bootloader now has an embedded wozmon! If you know its offset, you can jump to it from the app.
This commit is contained in:
62
mbv/hal/intc.cc
Normal file
62
mbv/hal/intc.cc
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "intc.h"
|
||||
|
||||
#include "pol0.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct IntC {
|
||||
volatile uint32_t ISR;
|
||||
volatile uint32_t IPR;
|
||||
volatile uint32_t IER;
|
||||
volatile uint32_t IAR;
|
||||
volatile uint32_t SIE;
|
||||
volatile uint32_t CIE;
|
||||
volatile uint32_t IVR;
|
||||
volatile uint32_t MER;
|
||||
volatile uint32_t IMR;
|
||||
volatile uint32_t ILR;
|
||||
|
||||
// the rest is not enabled
|
||||
};
|
||||
|
||||
IntC* intc = reinterpret_cast<IntC*>(INTC_BASE);
|
||||
Isr isrs[NIRQ] = {};
|
||||
|
||||
}
|
||||
|
||||
bool SetIrqEnabled(uint8_t irqn, bool enabled) {
|
||||
uint32_t mask = 1 << irqn;
|
||||
uint32_t ier = intc->IER;
|
||||
bool was_enabled = (ier & (~mask)) > 0;
|
||||
if (enabled) {
|
||||
intc->IER = ier | mask;
|
||||
} else {
|
||||
intc->IER = ier & (~mask);
|
||||
}
|
||||
|
||||
return was_enabled;
|
||||
}
|
||||
|
||||
void SetIsr(uint8_t irqn, Isr isr) {
|
||||
isrs[irqn] = isr;
|
||||
}
|
||||
|
||||
void EnableInterrupts() {
|
||||
intc->MER = 0x3;
|
||||
}
|
||||
|
||||
void InterruptHandler() {
|
||||
uint32_t ipr = intc->IPR;
|
||||
|
||||
for (int i = 0; i < NIRQ; i++) {
|
||||
uint32_t mask = 1 << i;
|
||||
|
||||
if ((ipr & mask) > 0) {
|
||||
// interrupt pending
|
||||
if (isrs[i] != nullptr) {
|
||||
isrs[i]();
|
||||
}
|
||||
intc->IAR = mask; // ack
|
||||
}
|
||||
}
|
||||
}
|
16
mbv/hal/intc.h
Normal file
16
mbv/hal/intc.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using Isr = void(*)(void);
|
||||
|
||||
/// Returns: true if the IRQ was previously enabled
|
||||
bool SetIrqEnabled(uint8_t irqn, bool enabled);
|
||||
|
||||
void SetIsr(uint8_t irqn, Isr isr);
|
||||
|
||||
// Call this once to enable all HW interrupts
|
||||
void EnableInterrupts();
|
||||
|
||||
// Feed this to the CPU's interrupt handler
|
||||
void InterruptHandler();
|
52
mbv/hal/interrupts.cc
Normal file
52
mbv/hal/interrupts.cc
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kMstatusMieMask = 1 << 3;
|
||||
constexpr uint32_t kMieExternalInterruptMask = 1 << 11;
|
||||
constexpr uint32_t kExternalInterruptCause = 0x0b;
|
||||
constexpr uint32_t kInterruptCauseMask = 0xff;
|
||||
|
||||
Isr external_handler = nullptr;
|
||||
|
||||
__attribute__((interrupt))
|
||||
void TrapHandler() {
|
||||
uint32_t mcause;
|
||||
uint32_t mip;
|
||||
asm volatile("csrr %0, mcause" : "=r"(mcause));
|
||||
asm volatile("csrr %0, mip" : "=r"(mip));
|
||||
|
||||
// check for external interrupt
|
||||
if ((mcause & kInterruptCauseMask) == kExternalInterruptCause) {
|
||||
if (external_handler != nullptr) {
|
||||
external_handler();
|
||||
}
|
||||
|
||||
mip &= ~(kMieExternalInterruptMask);
|
||||
asm volatile("csrw mip, %0" :: "r"(mip));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetExternalInterruptHandler(Isr handler) {
|
||||
external_handler = handler;
|
||||
}
|
||||
|
||||
void EnableExternalInterrupts() {
|
||||
uint32_t mstatus;
|
||||
uint32_t mie;
|
||||
Isr trap = TrapHandler;
|
||||
|
||||
asm volatile("csrr %0, mstatus" : "=r"(mstatus));
|
||||
asm volatile("csrr %0, mie" : "=r"(mie));
|
||||
|
||||
asm volatile("csrw mtvec, %0" :: "r"(trap));
|
||||
|
||||
mie |= kMieExternalInterruptMask;
|
||||
asm volatile("csrw mie, %0" :: "r"(mie));
|
||||
mstatus |= kMstatusMieMask;
|
||||
asm volatile("csrw mstatus, %0" :: "r"(mstatus));
|
||||
}
|
6
mbv/hal/interrupts.h
Normal file
6
mbv/hal/interrupts.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
using Isr = void(*)();
|
||||
|
||||
void SetExternalInterruptHandler(Isr handler);
|
||||
void EnableExternalInterrupts();
|
18
mbv/hal/pol0.h
Normal file
18
mbv/hal/pol0.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Platform definitions for pol0
|
||||
|
||||
// LED output
|
||||
#define GPIO0_BASE (0x40000000)
|
||||
|
||||
// /dev/ttyUSB1
|
||||
#define UART0_BASE (0x40600000)
|
||||
|
||||
// Interrupt controller
|
||||
#define INTC_BASE (0x41200000)
|
||||
|
||||
// It's uh.. a timer.
|
||||
#define TIMER0_BASE (0x41c00000)
|
||||
|
||||
// IRQs
|
||||
#define UART0_IRQN (0)
|
||||
#define TIMER0_IRQN (1)
|
||||
#define NIRQ (2)
|
69
mbv/hal/timer.h
Normal file
69
mbv/hal/timer.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct TimerControl {
|
||||
union {
|
||||
struct {
|
||||
uint32_t MDT0 : 1;
|
||||
uint32_t UDT0 : 1;
|
||||
uint32_t GENT0 : 1;
|
||||
uint32_t CAPT0 : 1;
|
||||
uint32_t ARHT0 : 1;
|
||||
uint32_t LOAD0 : 1;
|
||||
uint32_t ENIT0 : 1;
|
||||
uint32_t ENT0 : 1;
|
||||
uint32_t T0INT : 1;
|
||||
uint32_t PWMA0 : 1;
|
||||
uint32_t ENALL : 1;
|
||||
uint32_t CASC : 1;
|
||||
|
||||
uint32_t reserved : 20;
|
||||
};
|
||||
uint32_t raw;
|
||||
};
|
||||
};
|
||||
|
||||
struct Timer {
|
||||
volatile TimerControl TCSR0;
|
||||
volatile uint32_t TLR0;
|
||||
volatile uint32_t TCR0;
|
||||
|
||||
uint32_t _reserved;
|
||||
|
||||
volatile TimerControl TCSR1;
|
||||
volatile uint32_t TLR1;
|
||||
volatile uint32_t TCR1;
|
||||
|
||||
void EnableT1() {
|
||||
TCSR1.ARHT0 = 1;
|
||||
TCSR1.ENT0 = 1;
|
||||
}
|
||||
|
||||
uint32_t GetT1Ticks() { return TCR1; }
|
||||
|
||||
void SetupAsWdt(uint32_t timeout_ticks) {
|
||||
TLR0 = timeout_ticks;
|
||||
TCSR0.LOAD0 = 1; // reset counter
|
||||
TCSR0.UDT0 = 1; // count backwards from the load value
|
||||
TCSR0.ENIT0 = 1; // enable interrupt
|
||||
|
||||
TCSR0.LOAD0 = 0; // allow counter to run
|
||||
TCSR0.ENT0 = 1; // enable timer
|
||||
}
|
||||
|
||||
void Pet() {
|
||||
TCSR0.ENT0 = 0;
|
||||
TCSR0.LOAD0 = 1;
|
||||
TCSR0.LOAD0 = 0;
|
||||
TCSR0.ENT0 = 1;
|
||||
}
|
||||
|
||||
void ClearInterrupt() {
|
||||
TCSR0.T0INT = 0;
|
||||
}
|
||||
|
||||
static Timer* Instance(uint32_t base) {
|
||||
return reinterpret_cast<Timer*>(base);
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user