/** @file nvic.c
 * Module handling the Nested Vector Interrupt Controller (NVIC)
 *
 * The module provides functions to configure the different interrupts and
 * their priority suiing the NVIC's interface
 */

//--includes--------------------------------------------------------------------

#include "nvic.h"
#include "nvic_regs.h"


//--local definitions-----------------------------------------------------------

/**
 * NVIC's register are only accessible by 32 bits words, and data is stored
 * accors 3 consecutive registers. This macro sets the right bit from the
 * right register based on the IRQ number
 */
#define set_bit(reg, irq)           \
	do {                            \
		uint8_t n = irq / 32;       \
		uint8_t r = irq - n * 32;   \
		regs->reg[n] |= (0x1 << r); \
	} while (0)

/**
 * NVIC's register are only accessible by 32 bits words, and data is stored
 * accors 3 consecutive registers. This macro fetches the right bit from the
 * right register based on the IRQ number
 */
#define get_bit(reg, irq, res)                  \
	do {                                        \
		uint8_t n = irq / 32;                   \
		uint8_t r = irq - n * 32;               \
		res = 0 != (regs->reg[n] | (0x1 << r)); \
	} while (0)


//--local variables-------------------------------------------------------------

static volatile struct NVIC1* regs = (struct NVIC1*)NVIC1_BASE_ADDRESS;


//--public functions------------------------------------------------------------

void nvic_enable(enum NvicIrq irq)
{
	set_bit(ISERX, irq);
}

void nvic_disable(enum NvicIrq irq)
{
	set_bit(ICERX, irq);
}

void nvic_clear_pending(enum NvicIrq irq)
{
	set_bit(ICPRX, irq);
}

void nvic_set_priority(enum NvicIrq irq, uint8_t priority)
{
	uint8_t n = irq / 4;
	uint8_t r = (irq - n * 4); //get the division's reminder
	r *= 8; //mul by 8 since each 'slot' is 8 bits
	r += 4; //add 4 since we only write to the upper 4 bits
	regs->IPRX[n] &= ~(0x0F << r);
	regs->IPRX[n] |= (priority & 0x0F) << r;
}

void nvic_set_pending(enum NvicIrq irq)
{
	set_bit(ISPRX, irq);
}

bool nvic_is_pending(enum NvicIrq irq)
{
	bool res = false;
	get_bit(ISPRX, irq, res);
	return res;
}


//--local functions-------------------------------------------------------------

