#ifndef IO_H
#define IO_H

#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include "ioregs.h"
#include "picorv32.h"
#include "irq.h"

static inline void pause(void)
{
    /* Placeholder for anything that might want to be done while waiting */
}

static inline void set_leds(unsigned int leds)
{
    SYS_LED = leds;
}

static inline void set_led(unsigned int led, bool on)
{
    unsigned int leds = SYS_LED;
    unsigned int mask = 1 << led;

    leds &= ~mask;
    leds |= on ? mask : 0;
    SYS_LED = leds;
}

enum leds {
    LED_SDCARD,
    LED_DISKIO,
    LED_ABCBUS
};

static inline void __attribute__((noreturn)) reset(void)
{
    p_maskirq(~0, 0);		/* Block all interrupts */
    for (;;)
	asm volatile("ebreak");	/* Trigger system hang */
}

extern const uint32_t time_zero;

static inline uint32_t rdtime(void)
{
    uint32_t t;

    asm volatile("rdtime %0" : "=r" (t));
    return t;
}

static inline uint64_t rdtimeq(void)
{
    uint32_t l, h1, h0;

    asm volatile("rdtimeh %0; rdtime %1; %rdtimeh %2"
		 : "=r" (h1), "=r" (l), "=r" (h0));

    return ((uint64_t)(((int32_t)l < 0) ? h1 : h0) << 32) + l;
}

static inline void udelay(uint32_t us)
{
    uint32_t cycles = us * (CPU_HZ / 1000000);
    uint32_t start = rdtime();

    while (rdtime() - start < cycles)
	pause();
}

static inline void i2c_set_speed(unsigned int khz)
{
    I2C_DIVISOR = ((CPU_HZ/4000)-1)/khz;
}

static inline void wait_romcopy_done(void)
{
    while (~irqmask() & (1 << ROMCOPY_IRQ))
	pause();
}

#endif /* IO_H */
