#ifndef COMMON_H
#define COMMON_H

#include "compiler.h"
#include "sections.h"
#include "picorv32.h"
#include "irq.h"

#define min(a,b) Min(a,b)
#define max(a,b) Max(a,b)

/* memcpy() variants */

/* Use builtin memcpy and memset optimizations */
#define memset(s,c,n)	__builtin_memset(s,c,n)
#define memcpy(d,s,n)	__builtin_memcpy(d,s,n)
#define mempcpy(d,s,n)	__builtin_mempcpy(d,s,n)
#define memmove(d,s,n)	__builtin_memmove(d,s,n)

extern volatile void *memcpy_bytewise(volatile void *dst,
				      const volatile void *src, size_t len);
/*
 * The odd argument order allows memcpy() and mempcpy() to be implemented
 * as tail calls
 */
extern void *__memxcpy_aligned(void *retval,
			      const void * restrict src, size_t len,
			      void * restrict dst);
extern void *__memxcpy_bytewise(void *retval,
				const volatile void * restrict src, size_t len,
				void * restrict dst);


extern const size_t __rom_offset;
extern const uint32_t __dram_checksum;
extern const char __datestamp[];

extern char __esplink_start[],   __esplink_end[];
extern char __dram_init_start[], __dram_init_end[];
extern char __dram_bss_start[],  __dram_bss_end[];

static inline __constfunc size_t _align_down(size_t addr, size_t align)
{
    return addr & ~(align - 1);
}
#define align_down(a,l) ((__typeof__(a))_align_down((size_t)(a),(l)))

static inline __constfunc size_t _align_up(size_t addr, size_t align)
{
    return _align_down(addr + align - 1, align);
}
#define align_up(a,l)   ((__typeof__(a))_align_up((size_t)(a),(l)))

static uint32_t mask_lowest_set_bit(uint32_t mask)
{
    return mask & (mask-1);
}

static uint32_t lowest_set_bit(uint32_t mask)
{
    return mask - mask_lowest_set_bit(mask);
}

static const char *notempty(const char *str)
{
    return str ? str : "";
}

struct esplink_head;
extern struct esplink_head esplink_head;
extern uint32_t esplink[];

extern no_return _die(void);
extern no_return exit(int);
extern no_return _exit(int);

/* Value of an absolute symbol with one more _ than here given */
#define abssymval(x)				\
    static inline size_t x (void) {		\
	extern const char _ ## x [];		\
	return (size_t) _ ## x;			\
    }

extern const uint8_t _end[];
extern void *_sbrk(ptrdiff_t);

extern uint32_t timer_irq_start;
static inline uint32_t timer_count(void)
{
    extern volatile uint32_t timer_irq_count;
    return timer_irq_count;
}

extern void init(void);
extern void heap_init(void);

extern void mount_abcdrives(void);

extern void read_rtc(void);
extern void write_rtc(void);
extern volatile bool do_write_rtc;

extern void romcopy_download(void *, size_t, size_t);
extern void romcopy_bzero(void *, size_t);
extern void rom_print_serial(void);
extern qword_t rom_serial;

extern void run_test_image(void);

extern void rom_flash_from_memory(void *, size_t);
extern void rom_flash_from_sdcard(void);

extern no_return shutdown(unsigned int);

#endif /* COMMON_H */
