#include "fw.h"
#include "io.h"
#include "abcio.h"
#include "sys.h"
#include "console.h"

volatile uint32_t timer_irq_count;
IRQHANDLER(sysclock)
{
    uint32_t count = timer_irq_count;

    count++;
    timer_irq_count = count;
#ifdef TEST
    set_leds(count >> 3); /* 4 Hz */
#endif
}

static no_return killed(const char *how, size_t pc)
{
    con_printf("ERROR: %s at 0x%08x\n", how, pc);

    con_flush();
    udelay(5000000);
    reset();
}

IRQHANDLER(BUSERR)
{
    killed("misaligned", pc);
}

IRQHANDLER(EBREAK)
{
    killed("invalid instruction", pc);
}

uint32_t timer_irq_start;
void init(void)
{
    static const char hello[] =
	"\n\n*** Hello, World! ***\n"
	"MAX80 "
#ifdef TEST
	"testing"
#endif
	"firmware compiled on: " __DATE__ " " __TIME__ "\n";

    set_leds(-1U);

    /* Start ROM copy engine and unmask fatal exceptions */
    unmask_irqs((1U << ROMCOPY_IRQ)|(1U << EBREAK_IRQ)|(1U << BUSERR_IRQ));

    /* Enable internal timer */
    timer_irq_start = rdtime();
    unmask_irq(SYSCLOCK_IRQ);

    /* This needs to be done as early as possible!!! */
    abc_init_memmap();

    con_set_baudrate(115200);
    con_puts(hello);

    if (SYS_MAGIC != SYS_MAGIC_MAX80) {
	con_puts("Not a MAX80 board?!?!\n\n");
	_die();
    } else {
	uint32_t boardcfg = SYS_BOARDCFG;
	con_printf("MAX80 ver %u.%u rework flags %04x\n\n",
		   (uint8_t)(boardcfg >> 24),
		   (uint8_t)(boardcfg >> 16),
		   (uint16_t)boardcfg);
    }

    read_rtc();

    abcdisk_init();
    abc_init();

    set_leds(0);

    /* Release WAIT# if asserted */
    ABC_BUSCTL = 0;
}
