CS107e libpi source files

/*
 * Functions for Raspberry Pi ARM Timer.
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 *         Dawson Engler <engler@cs.stanford.edu>
 *
 * Date: April 20, 2016
*/
#include "armtimer.h"
#include <stdint.h>

/*
 * See BCM p 196 (unfortunately the documentation is wrong in several places)
 *
 * This timer has two parts: a free running counter and a count-down timer.
 * The timer is always running in free running mode.
 *
 * In this module, we implement the count-down timer. Interval is set as
 * load/re-load, will count down from there to zero. At zero, will report
 * overflow and generate interrupt (if interrupts enabled)
 *
 * The timer and counter are based on the APB clock, which on the
 * Raspberry Pi is 250 Mhz
 *
 * Some errors in the documentation:
 *  (1) the counters are either 32-bit (not 23-bit) or 16-bit
 *  (2) the effect of pre-scale bits (3:2) in the control register is unclear.
 */

struct armtimer_t {
    uint32_t load;                  // writing immediately loads the counter
    uint32_t value;                 // current counter value, read only
    struct {
        uint32_t : 1,
                 timer_is_32_bit: 1,         // 0 -> 16-bit, 1 -> 32 bit
                 : 3,
                 enable_timer_interrupt: 1,  // 1 = timer interrupts enabled
                 : 1,
                 enable_timer: 1,            // 1 - timer enabled
                 run_in_debug: 1,            // 1 = run timer in arm debug mode/halt
                 free_counter_enable: 1,     // 1 = free running counter enabled
                 : 6,
                 free_counter_prescale: 8;   // prescalar for the free running counter
        // clk/(prescale+1)
    } control;
    uint32_t clear_event;           // clear overflow/interrupt, write only
    uint32_t overflow;              // overflow/interrupt pending, read only
    uint32_t irq;                   // pending & interrupt enabled, read only
    uint32_t reload;                // value to be reloaded when value hits 0
    uint32_t prescale;              // prescaler for countdown timer clk/(prescale+1)
    uint32_t free_counter_value;    // free running counter value
};

#define ARMTIMER_BASE 0x2000B400;

static volatile struct armtimer_t * const armtimer = (struct armtimer_t *)ARMTIMER_BASE;


/* Cute hack: compile-time assertion . */
#define AssertNow(x) switch(1) { case (x): case 0: ; }

/*
 * initialize armtimer
 *
 * ticks is the number of usecs between overflows/interrupts
 *
 * timer is initialized, but not enabled. interrupts are disabled.
 *
 */
void armtimer_init(unsigned int ticks) {
    // make sure bit-fields are within 1 word
    AssertNow(sizeof armtimer->control == 4);

    armtimer->control.enable_timer = 0;
    armtimer->control.enable_timer_interrupt = 0;
    armtimer->clear_event = 0;
    armtimer->control.timer_is_32_bit = 1;

    // setup up timer it counts once per microsecond
    armtimer->prescale = (250 - 1); // 250 000 000 / 250 = 1 000 000 = 1 usec

    // ticks are number of microseconds between overflows/interrupts
    armtimer->load = ticks - 1;  // load value is immediately loaded into the counter
    armtimer->reload = ticks - 1; // reload value is loaded into the counter when it hits 0
}

/*
 * set timer prescalar (apbclock/divisor)
 *
 * the timer counts at a rate equal to the ABP clock divided by the divisor.
 * the APB clock on the Raspberry Pi runs at 250 Mhz.  thus, if the divisor
 * equals 250, the timer will count once per usec.
 *
 * The prescale register is 10-bits
 *
 * The reset value of this register is 0x7D so gives a divide by 126.
 */
__attribute__((unused)) static void armtimer_set_prescalar(unsigned int divisor) {
    armtimer->prescale = divisor - 1;
}

void armtimer_enable(void) {
    armtimer->control.enable_timer = 1;
}

void armtimer_disable(void) {
    armtimer->control.enable_timer = 0;
}

void armtimer_enable_interrupts(void) {
    armtimer->control.enable_timer_interrupt = 1;
}

void armtimer_disable_interrupts(void) {
    armtimer->control.enable_timer_interrupt = 0;
}

unsigned int armtimer_get_count(void) {
    return armtimer->value;
}

bool armtimer_check_overflow(void) {
    return armtimer->overflow != 0;
}

void armtimer_clear_event(void) {
    armtimer->clear_event = 1;
}

bool armtimer_check_and_clear_overflow(void) {
    bool had_event = armtimer_check_overflow();
    if (had_event) {
        armtimer_clear_event();
    }
    return had_event;
}

bool armtimer_check_interrupt(void) {
    return armtimer->irq != 0;
}

bool armtimer_check_and_clear_interrupt(void) {
    bool had_event = armtimer_check_interrupt();
    if (had_event) {
        armtimer_clear_event();
    }
    return had_event;
}

/*
 * Assembly routine to count leading zero bits
 * Author: Philip Levis
 */

.global count_leading_zeroes
count_leading_zeroes:
    clz r0, r0
    bx lr

/*
 * Access to font pixel data stored as a bitmap.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Last modified: 3/17/16
 */

#include "font.h"

typedef struct  {
    unsigned char first_char, last_char;
    size_t glyph_width, glyph_height;
    unsigned char pixel_data[];
} font_t;

static const font_t font_default;
static const font_t *g_font = &font_default;

size_t font_get_glyph_height(void) {
    return g_font->glyph_height;
}

size_t font_get_glyph_width(void) {
    return g_font->glyph_width;
}

size_t font_get_glyph_size(void) {
    return font_get_glyph_width() * font_get_glyph_height();
}

/* Extract glyph pixels for requested character from font bitmap.
 * Read bits from font bitmap and store into array of bytes, one byte per pixel.
 * Use 0xff byte for on pixel, 0x0 for off pixel.
 */
bool font_get_glyph(char ch, unsigned char buf[], size_t buflen) {
    if ((ch != ' ' && (ch < g_font->first_char || ch > g_font->last_char)) || (buflen != font_get_glyph_size())) {
        return false;
    }

    if (ch == ' ') { // Handle space as special case, return all-off image
        for (int i = 0; i < buflen; i++) {
            buf[i] = 0;
        }
    } else {
        int index = 0;
        int nbits_in_row = (g_font->last_char - g_font->first_char + 1) * font_get_glyph_width();
        int x_offset = (ch - g_font->first_char);
        for (int y = 0; y < font_get_glyph_height(); y++) {
            for (int x = 0; x < font_get_glyph_width(); x++) {
                int bit_index = y * nbits_in_row + x_offset * font_get_glyph_width() + x;
                int bit_start = bit_index / 8;
                int bit_offset = bit_index % 8;
                // extract single bit for this pixel from bitmap
                int val = g_font->pixel_data[bit_start] & (1 << (7 - bit_offset));
                // use 0xff for on pixel, 0x0 for off pixel
                buf[index++] = val != 0 ? 0xFF : 0x00;
            }
        }
    }
    return true;
}

/*
 * Apple II font stored as a bitmap.
 * Each character is 14 bits wide and 16 bits tall (long story
 * about some C conversion).
 *
 * Generated from a screenshot of the original font, turned into
 * a 32-bit color C structure with GIMP, then turned into a bitmap
 * C structure with a simple C program.
 */
static const font_t font_default = {
    .first_char = 0x21, .last_char = 0x7F,
    .glyph_width = 14, .glyph_height = 16,
    .pixel_data = {
        0x03, 0x00, 0x33, 0x00, 0xcc, 0x00, 0xc0, 0x3c,
        0x00, 0x30, 0x00, 0x30, 0x00, 0xc0, 0x03, 0x00,
        0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x03, 0xf0, 0x03, 0x00, 0x3f, 0x03,
        0xff, 0x00, 0x30, 0x3f, 0xf0, 0x0f, 0xc3, 0xff,
        0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00,
        0x30, 0x00, 0x00, 0x30, 0x00, 0xfc, 0x03, 0xf0,
        0x03, 0x00, 0xff, 0x00, 0xfc, 0x0f, 0xf0, 0x3f,
        0xf0, 0xff, 0xc0, 0xff, 0x0c, 0x0c, 0x0f, 0xc0,
        0x00, 0xc3, 0x03, 0x0c, 0x00, 0x30, 0x30, 0xc0,
        0xc0, 0xfc, 0x0f, 0xf0, 0x0f, 0xc0, 0xff, 0x00,
        0xfc, 0x0f, 0xfc, 0x30, 0x30, 0xc0, 0xc3, 0x03,
        0x0c, 0x0c, 0x30, 0x30, 0xff, 0xc3, 0xff, 0x00,
        0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x03, 0x00,
        0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x0c, 0x00,
        0x00, 0x0f, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00,
        0x03, 0x03, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00,
        0xc0, 0x3f, 0x00, 0x3c, 0xc0, 0x00, 0x00, 0xc0,
        0x0c, 0xc0, 0x33, 0x00, 0x30, 0x0f, 0x00, 0x0c,
        0x00, 0x0c, 0x00, 0x30, 0x00, 0xc0, 0x03, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0xfc, 0x00, 0xc0, 0x0f, 0xc0, 0xff, 0xc0,
        0x0c, 0x0f, 0xfc, 0x03, 0xf0, 0xff, 0xc0, 0xfc,
        0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
        0x00, 0x0c, 0x00, 0x3f, 0x00, 0xfc, 0x00, 0xc0,
        0x3f, 0xc0, 0x3f, 0x03, 0xfc, 0x0f, 0xfc, 0x3f,
        0xf0, 0x3f, 0xc3, 0x03, 0x03, 0xf0, 0x00, 0x30,
        0xc0, 0xc3, 0x00, 0x0c, 0x0c, 0x30, 0x30, 0x3f,
        0x03, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0x3f, 0x03,
        0xff, 0x0c, 0x0c, 0x30, 0x30, 0xc0, 0xc3, 0x03,
        0x0c, 0x0c, 0x3f, 0xf0, 0xff, 0xc0, 0x00, 0x0f,
        0xfc, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
        0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
        0xc0, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0xc0,
        0xc0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x30, 0x0f,
        0xc0, 0x0f, 0x30, 0x00, 0x00, 0x30, 0x03, 0x30,
        0x0c, 0xc0, 0x3f, 0xc3, 0xc3, 0x0c, 0xc0, 0x03,
        0x00, 0x30, 0x00, 0x0c, 0x0c, 0xcc, 0x03, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc0,
        0xc0, 0xf0, 0x0c, 0x0c, 0x00, 0x30, 0x0f, 0x03,
        0x00, 0x03, 0x00, 0x00, 0x30, 0xc0, 0xc3, 0x03,
        0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
        0xc0, 0x30, 0x30, 0xc0, 0xc0, 0xcc, 0x0c, 0x0c,
        0x30, 0x30, 0xc0, 0xc3, 0x00, 0x0c, 0x00, 0x30,
        0x00, 0xc0, 0xc0, 0x30, 0x00, 0x0c, 0x30, 0xc0,
        0xc0, 0x03, 0xcf, 0x0c, 0x0c, 0x30, 0x30, 0xc0,
        0xc3, 0x03, 0x0c, 0x0c, 0x30, 0x30, 0x0c, 0x03,
        0x03, 0x0c, 0x0c, 0x30, 0x30, 0xc0, 0xc3, 0x03,
        0x00, 0x0c, 0x3c, 0x00, 0xc0, 0x00, 0x0f, 0x00,
        0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0c, 0x00,
        0x00, 0x00, 0x00, 0xc0, 0x00, 0x03, 0x0c, 0x00,
        0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
        0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x3c, 0x0c,
        0xf0, 0x33, 0x30, 0x0c, 0x00, 0xcc, 0x03, 0x30,
        0x0f, 0xf0, 0xf0, 0xc3, 0x30, 0x00, 0xc0, 0x0c,
        0x00, 0x03, 0x03, 0x33, 0x00, 0xc0, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x30, 0x3c,
        0x03, 0x03, 0x00, 0x0c, 0x03, 0xc0, 0xc0, 0x00,
        0xc0, 0x00, 0x0c, 0x30, 0x30, 0xc0, 0xc0, 0x00,
        0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x0c,
        0x0c, 0x30, 0x30, 0x33, 0x03, 0x03, 0x0c, 0x0c,
        0x30, 0x30, 0xc0, 0x03, 0x00, 0x0c, 0x00, 0x30,
        0x30, 0x0c, 0x00, 0x03, 0x0c, 0x30, 0x30, 0x00,
        0xf3, 0xc3, 0x03, 0x0c, 0x0c, 0x30, 0x30, 0xc0,
        0xc3, 0x03, 0x0c, 0x0c, 0x03, 0x00, 0xc0, 0xc3,
        0x03, 0x0c, 0x0c, 0x30, 0x30, 0xc0, 0xc0, 0x03,
        0x0f, 0x00, 0x30, 0x00, 0x03, 0xc0, 0x00, 0x00,
        0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
        0x00, 0x30, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x30,
        0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x03, 0xc0, 0x03, 0x00, 0x0f, 0x03, 0x3c, 0x0c,
        0xcc, 0x03, 0x00, 0x33, 0x03, 0xff, 0x0c, 0xc0,
        0x00, 0xc0, 0xcc, 0x00, 0x30, 0x0c, 0x00, 0x00,
        0x30, 0x3f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x0c, 0x0c, 0x3c, 0x03, 0x00, 0x00,
        0xc0, 0x0c, 0x03, 0x30, 0x3f, 0xc0, 0xc0, 0x00,
        0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x0c, 0x00, 0x30,
        0x03, 0x00, 0x3f, 0xf0, 0x03, 0x00, 0x0c, 0x0c,
        0xcc, 0x30, 0x30, 0xc0, 0xc3, 0x00, 0x0c, 0x0c,
        0x30, 0x00, 0xc0, 0x03, 0x00, 0x0c, 0x0c, 0x03,
        0x00, 0x00, 0xc3, 0x30, 0x0c, 0x00, 0x33, 0x30,
        0xf0, 0xc3, 0x03, 0x0c, 0x0c, 0x30, 0x30, 0xc0,
        0xc3, 0x00, 0x00, 0xc0, 0x30, 0x30, 0xc0, 0xc3,
        0x03, 0x03, 0x30, 0x0c, 0xc0, 0x03, 0x03, 0xc0,
        0x03, 0x00, 0x00, 0xf0, 0x0c, 0x00, 0x00, 0x00,
        0x30, 0x0f, 0xc0, 0xff, 0x00, 0xff, 0x03, 0xfc,
        0x0f, 0xc0, 0x30, 0x00, 0xfc, 0x0f, 0xf0, 0x0f,
        0x00, 0x0f, 0x03, 0x03, 0x00, 0xc0, 0x3c, 0xf0,
        0xff, 0x00, 0xfc, 0x0f, 0xf0, 0x0f, 0xf0, 0xcf,
        0xc0, 0xff, 0x0f, 0xf0, 0x30, 0x30, 0xc0, 0xc3,
        0x03, 0x0c, 0x0c, 0x30, 0x30, 0xff, 0xc0, 0xf0,
        0x00, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0xcc, 0x00,
        0xc0, 0x0c, 0xc0, 0xff, 0xc3, 0x30, 0x00, 0x30,
        0x33, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x0c, 0x0f,
        0xc0, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x03, 0x0f, 0x00, 0xc0, 0x00, 0x30, 0x03,
        0x00, 0xcc, 0x0f, 0xf0, 0x30, 0x00, 0x03, 0x03,
        0x03, 0x0c, 0x0c, 0x03, 0x00, 0x0c, 0x00, 0xc0,
        0x0f, 0xfc, 0x00, 0xc0, 0x03, 0x03, 0x33, 0x0c,
        0x0c, 0x30, 0x30, 0xc0, 0x03, 0x03, 0x0c, 0x00,
        0x30, 0x00, 0xc0, 0x03, 0x03, 0x00, 0xc0, 0x00,
        0x30, 0xcc, 0x03, 0x00, 0x0c, 0xcc, 0x3c, 0x30,
        0xc0, 0xc3, 0x03, 0x0c, 0x0c, 0x30, 0x30, 0xc0,
        0x00, 0x30, 0x0c, 0x0c, 0x30, 0x30, 0xc0, 0xc0,
        0xcc, 0x03, 0x30, 0x00, 0xc0, 0xf0, 0x00, 0xc0,
        0x00, 0x3c, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x03,
        0xf0, 0x3f, 0xc0, 0x3f, 0xc0, 0xff, 0x03, 0xf0,
        0x0c, 0x00, 0x3f, 0x03, 0xfc, 0x03, 0xc0, 0x03,
        0xc0, 0xc0, 0xc0, 0x30, 0x0f, 0x3c, 0x3f, 0xc0,
        0x3f, 0x03, 0xfc, 0x03, 0xfc, 0x33, 0xf0, 0x3f,
        0xc3, 0xfc, 0x0c, 0x0c, 0x30, 0x30, 0xc0, 0xc3,
        0x03, 0x0c, 0x0c, 0x3f, 0xf0, 0x3c, 0x00, 0x30,
        0x00, 0xf0, 0x00, 0x00, 0x33, 0x00, 0x30, 0x00,
        0x00, 0x0c, 0xc0, 0x3f, 0x00, 0x30, 0x03, 0x00,
        0x00, 0x00, 0xc0, 0x00, 0x03, 0x00, 0xc0, 0x3f,
        0xf0, 0x00, 0x03, 0xff, 0x00, 0x00, 0x03, 0x00,
        0xcc, 0xc0, 0x30, 0x00, 0xf0, 0x03, 0xc0, 0xc3,
        0x00, 0x03, 0x0f, 0xf0, 0x03, 0x00, 0x3f, 0x00,
        0xff, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
        0x00, 0x0c, 0x03, 0x00, 0xcf, 0xc3, 0x03, 0x0f,
        0xf0, 0x30, 0x00, 0xc0, 0xc3, 0xfc, 0x0f, 0xf0,
        0x30, 0x00, 0xff, 0xc0, 0x30, 0x00, 0x0c, 0x3c,
        0x00, 0xc0, 0x03, 0x33, 0x0c, 0xcc, 0x30, 0x30,
        0xff, 0x03, 0x03, 0x0f, 0xf0, 0x0f, 0xc0, 0x0c,
        0x03, 0x03, 0x0c, 0x0c, 0x33, 0x30, 0x0c, 0x00,
        0x30, 0x00, 0xc0, 0x3c, 0x00, 0x0c, 0x00, 0x0f,
        0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0c,
        0x0c, 0x30, 0x00, 0xc0, 0xc3, 0x03, 0x0f, 0xf0,
        0x30, 0x30, 0xc0, 0xc0, 0x30, 0x00, 0x30, 0x30,
        0xc0, 0x0c, 0x03, 0x33, 0x0c, 0x0c, 0x30, 0x30,
        0xc0, 0xc3, 0x03, 0x0f, 0x00, 0x30, 0x00, 0x30,
        0x03, 0x03, 0x0c, 0x0c, 0x30, 0x30, 0x33, 0x03,
        0x03, 0x00, 0x30, 0x3c, 0x00, 0x0c, 0x00, 0x0f,
        0x00, 0x00, 0x33, 0x30, 0x0c, 0x00, 0x00, 0x03,
        0x30, 0x0f, 0xc0, 0x0c, 0x00, 0xc0, 0x00, 0x00,
        0x30, 0x00, 0x00, 0xc0, 0x30, 0x0f, 0xfc, 0x00,
        0x00, 0xff, 0xc0, 0x00, 0x00, 0xc0, 0x33, 0x30,
        0x0c, 0x00, 0x3c, 0x00, 0xf0, 0x30, 0xc0, 0x00,
        0xc3, 0xfc, 0x00, 0xc0, 0x0f, 0xc0, 0x3f, 0xc0,
        0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03,
        0x00, 0xc0, 0x33, 0xf0, 0xc0, 0xc3, 0xfc, 0x0c,
        0x00, 0x30, 0x30, 0xff, 0x03, 0xfc, 0x0c, 0x00,
        0x3f, 0xf0, 0x0c, 0x00, 0x03, 0x0f, 0x00, 0x30,
        0x00, 0xcc, 0xc3, 0x33, 0x0c, 0x0c, 0x3f, 0xc0,
        0xc0, 0xc3, 0xfc, 0x03, 0xf0, 0x03, 0x00, 0xc0,
        0xc3, 0x03, 0x0c, 0xcc, 0x03, 0x00, 0x0c, 0x00,
        0x30, 0x0f, 0x00, 0x03, 0x00, 0x03, 0xc0, 0xcc,
        0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x0c,
        0x00, 0x30, 0x30, 0xc0, 0xc3, 0xfc, 0x0c, 0x0c,
        0x30, 0x30, 0x0c, 0x00, 0x0c, 0x0c, 0x30, 0x03,
        0x00, 0xcc, 0xc3, 0x03, 0x0c, 0x0c, 0x30, 0x30,
        0xc0, 0xc3, 0xc0, 0x0c, 0x00, 0x0c, 0x00, 0xc0,
        0xc3, 0x03, 0x0c, 0x0c, 0x0c, 0xc0, 0xc0, 0xc0,
        0x0c, 0x0f, 0x00, 0x03, 0x00, 0x03, 0xc0, 0x00,
        0x0c, 0xcc, 0x03, 0x00, 0x00, 0x03, 0xff, 0x00,
        0xcc, 0x0c, 0x00, 0xcc, 0xc0, 0x00, 0x0c, 0x00,
        0x00, 0x30, 0x3f, 0x00, 0x30, 0x00, 0xc0, 0x00,
        0x00, 0x00, 0x00, 0xc0, 0x0f, 0x0c, 0x03, 0x00,
        0x30, 0x00, 0x03, 0x0f, 0xfc, 0x00, 0x30, 0xc0,
        0xc0, 0xc0, 0x0c, 0x0c, 0x00, 0x30, 0x0c, 0x00,
        0x30, 0x03, 0x00, 0x3f, 0xf0, 0x03, 0x00, 0x30,
        0x0c, 0xf0, 0x3f, 0xf0, 0xc0, 0xc3, 0x00, 0x0c,
        0x0c, 0x30, 0x00, 0xc0, 0x03, 0x0f, 0x0c, 0x0c,
        0x03, 0x00, 0x00, 0xc3, 0x30, 0x0c, 0x00, 0x30,
        0x30, 0xc3, 0xc3, 0x03, 0x0c, 0x00, 0x33, 0x30,
        0xcc, 0x00, 0x03, 0x00, 0xc0, 0x30, 0x30, 0xc0,
        0xc3, 0x33, 0x03, 0x30, 0x03, 0x00, 0x30, 0x03,
        0xc0, 0x00, 0x30, 0x00, 0xf0, 0xc0, 0xc0, 0x00,
        0x00, 0x00, 0x0f, 0xf0, 0xc0, 0xc3, 0x00, 0x0c,
        0x0c, 0x3f, 0xf0, 0x30, 0x03, 0x03, 0x0c, 0x0c,
        0x03, 0x00, 0x03, 0x03, 0xf0, 0x00, 0xc0, 0x33,
        0x30, 0xc0, 0xc3, 0x03, 0x0c, 0x0c, 0x30, 0x30,
        0xc0, 0x00, 0xfc, 0x03, 0x00, 0x30, 0x30, 0xc0,
        0xc3, 0x33, 0x00, 0xc0, 0x30, 0x30, 0x0c, 0x00,
        0xf0, 0x00, 0xc0, 0x03, 0xc0, 0x00, 0x00, 0xcc,
        0x00, 0xc0, 0x00, 0x00, 0xff, 0xc0, 0x33, 0x03,
        0x00, 0x33, 0x30, 0x00, 0x03, 0x00, 0x00, 0x0c,
        0x0f, 0xc0, 0x0c, 0x00, 0x30, 0x00, 0x00, 0x00,
        0x00, 0x30, 0x03, 0xc3, 0x00, 0xc0, 0x0c, 0x00,
        0x00, 0xc3, 0xff, 0x00, 0x0c, 0x30, 0x30, 0x30,
        0x03, 0x03, 0x00, 0x0c, 0x03, 0x00, 0x0c, 0x00,
        0xc0, 0x0f, 0xfc, 0x00, 0xc0, 0x0c, 0x03, 0x3c,
        0x0f, 0xfc, 0x30, 0x30, 0xc0, 0x03, 0x03, 0x0c,
        0x00, 0x30, 0x00, 0xc3, 0xc3, 0x03, 0x00, 0xc0,
        0x00, 0x30, 0xcc, 0x03, 0x00, 0x0c, 0x0c, 0x30,
        0xf0, 0xc0, 0xc3, 0x00, 0x0c, 0xcc, 0x33, 0x00,
        0x00, 0xc0, 0x30, 0x0c, 0x0c, 0x30, 0x30, 0xcc,
        0xc0, 0xcc, 0x00, 0xc0, 0x0c, 0x00, 0xf0, 0x00,
        0x0c, 0x00, 0x3c, 0x30, 0x30, 0x00, 0x00, 0x00,
        0x03, 0xfc, 0x30, 0x30, 0xc0, 0x03, 0x03, 0x0f,
        0xfc, 0x0c, 0x00, 0xc0, 0xc3, 0x03, 0x00, 0xc0,
        0x00, 0xc0, 0xfc, 0x00, 0x30, 0x0c, 0xcc, 0x30,
        0x30, 0xc0, 0xc3, 0x03, 0x0c, 0x0c, 0x30, 0x00,
        0x3f, 0x00, 0xc0, 0x0c, 0x0c, 0x30, 0x30, 0xcc,
        0xc0, 0x30, 0x0c, 0x0c, 0x03, 0x00, 0x3c, 0x00,
        0x30, 0x00, 0xf0, 0x00, 0x00, 0x33, 0x00, 0x00,
        0x00, 0x00, 0x0c, 0xc0, 0xff, 0x03, 0x0f, 0x0c,
        0x30, 0x00, 0x00, 0x30, 0x00, 0x0c, 0x0c, 0xcc,
        0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30,
        0x00, 0xc0, 0xc0, 0x30, 0x0c, 0x00, 0x30, 0x30,
        0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x00, 0xc0,
        0xc0, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00,
        0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x03, 0x03,
        0x0c, 0x0c, 0x30, 0x30, 0xc0, 0xc3, 0x00, 0x0c,
        0x00, 0x30, 0x30, 0xc0, 0xc0, 0x30, 0x0c, 0x0c,
        0x30, 0xc0, 0xc0, 0x03, 0x03, 0x0c, 0x0c, 0x30,
        0x30, 0xc0, 0x03, 0x0c, 0x0c, 0x30, 0x30, 0x30,
        0x0c, 0x03, 0x03, 0x03, 0x30, 0x3c, 0xf0, 0xc0,
        0xc0, 0x30, 0x0c, 0x00, 0x3c, 0x00, 0x00, 0xc0,
        0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
        0x0c, 0x0c, 0x30, 0x00, 0xc0, 0xc3, 0x00, 0x03,
        0x00, 0x0f, 0xf0, 0xc0, 0xc0, 0x30, 0x00, 0x30,
        0x30, 0xc0, 0x0c, 0x03, 0x33, 0x0c, 0x0c, 0x30,
        0x30, 0xff, 0x00, 0xff, 0x0c, 0x00, 0x00, 0x30,
        0x30, 0xc3, 0x0f, 0x03, 0x30, 0x33, 0x30, 0x33,
        0x00, 0xff, 0x03, 0x00, 0x0f, 0x00, 0x0c, 0x00,
        0x3c, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00,
        0x03, 0x30, 0x3f, 0xc0, 0xc3, 0xc3, 0x0c, 0x00,
        0x00, 0x0c, 0x00, 0x03, 0x03, 0x33, 0x00, 0xc0,
        0x03, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x30,
        0x30, 0x0c, 0x03, 0x00, 0x0c, 0x0c, 0x00, 0xc0,
        0xc0, 0xc3, 0x03, 0x03, 0x00, 0x30, 0x30, 0x03,
        0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00,
        0x30, 0x00, 0x00, 0x30, 0x00, 0xc0, 0xc3, 0x03,
        0x0c, 0x0c, 0x30, 0x30, 0xc0, 0x03, 0x00, 0x0c,
        0x0c, 0x30, 0x30, 0x0c, 0x03, 0x03, 0x0c, 0x30,
        0x30, 0x00, 0xc0, 0xc3, 0x03, 0x0c, 0x0c, 0x30,
        0x00, 0xc3, 0x03, 0x0c, 0x0c, 0x0c, 0x03, 0x00,
        0xc0, 0xc0, 0xcc, 0x0f, 0x3c, 0x30, 0x30, 0x0c,
        0x03, 0x00, 0x0f, 0x00, 0x00, 0x30, 0x03, 0xc0,
        0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc3, 0x03,
        0x0c, 0x00, 0x30, 0x30, 0xc0, 0x00, 0xc0, 0x03,
        0xfc, 0x30, 0x30, 0x0c, 0x00, 0x0c, 0x0c, 0x30,
        0x03, 0x00, 0xcc, 0xc3, 0x03, 0x0c, 0x0c, 0x3f,
        0xc0, 0x3f, 0xc3, 0x00, 0x00, 0x0c, 0x0c, 0x30,
        0xc3, 0xc0, 0xcc, 0x0c, 0xcc, 0x0c, 0xc0, 0x3f,
        0xc0, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x0f, 0x00,
        0x00, 0x0c, 0xcc, 0x03, 0x00, 0x00, 0x00, 0xcc,
        0x00, 0xc0, 0x00, 0xf0, 0x3c, 0xc0, 0x00, 0x00,
        0xc0, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00,
        0x00, 0x00, 0x0c, 0x00, 0x00, 0x03, 0xf0, 0x0f,
        0xc0, 0xff, 0xc0, 0xfc, 0x00, 0x30, 0x0f, 0xc0,
        0x3f, 0x00, 0xc0, 0x03, 0xf0, 0x3f, 0x00, 0x00,
        0x00, 0xc0, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00,
        0x30, 0x03, 0xfc, 0x30, 0x30, 0xff, 0x00, 0xfc,
        0x0f, 0xf0, 0x3f, 0xf0, 0xc0, 0x00, 0xff, 0x0c,
        0x0c, 0x0f, 0xc0, 0x3f, 0x03, 0x03, 0x0f, 0xfc,
        0x30, 0x30, 0xc0, 0xc0, 0xfc, 0x0c, 0x00, 0x0f,
        0x30, 0xc0, 0xc0, 0xfc, 0x00, 0xc0, 0x0f, 0xc0,
        0x0c, 0x03, 0x03, 0x0c, 0x0c, 0x03, 0x00, 0xff,
        0xc3, 0xff, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0xff,
        0x03, 0xfc, 0x0f, 0xf0, 0x30, 0x00, 0x03, 0x0c,
        0x0c, 0x0f, 0xc0, 0xc3, 0x03, 0x03, 0x03, 0xf0,
        0x30, 0x30, 0xc0, 0xc0, 0xfc, 0x0c, 0x00, 0x00,
        0x30, 0xc0, 0x03, 0xfc, 0x00, 0xf0, 0x0f, 0x30,
        0x0c, 0x03, 0xcf, 0x0c, 0x0c, 0x00, 0x30, 0xff,
        0xc0, 0x3f, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0xc0, 0x00, 0x00, 0x33, 0x00, 0x30,
        0x00, 0x3c, 0x0f, 0x30, 0x00, 0x00, 0x30, 0x00,
        0xc0, 0x03, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
        0x03, 0x00, 0x00, 0x00, 0xfc, 0x03, 0xf0, 0x3f,
        0xf0, 0x3f, 0x00, 0x0c, 0x03, 0xf0, 0x0f, 0xc0,
        0x30, 0x00, 0xfc, 0x0f, 0xc0, 0x00, 0x00, 0x30,
        0x00, 0x0c, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
        0xff, 0x0c, 0x0c, 0x3f, 0xc0, 0x3f, 0x03, 0xfc,
        0x0f, 0xfc, 0x30, 0x00, 0x3f, 0xc3, 0x03, 0x03,
        0xf0, 0x0f, 0xc0, 0xc0, 0xc3, 0xff, 0x0c, 0x0c,
        0x30, 0x30, 0x3f, 0x03, 0x00, 0x03, 0xcc, 0x30,
        0x30, 0x3f, 0x00, 0x30, 0x03, 0xf0, 0x03, 0x00,
        0xc0, 0xc3, 0x03, 0x00, 0xc0, 0x3f, 0xf0, 0xff,
        0xc0, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x03, 0xfc, 0x3f, 0xc0, 0x3f, 0xc0, 0xff,
        0x03, 0xfc, 0x0c, 0x00, 0x00, 0xc3, 0x03, 0x03,
        0xf0, 0x30, 0xc0, 0xc0, 0xc0, 0xfc, 0x0c, 0x0c,
        0x30, 0x30, 0x3f, 0x03, 0x00, 0x00, 0x0c, 0x30,
        0x00, 0xff, 0x00, 0x3c, 0x03, 0xcc, 0x03, 0x00,
        0xf3, 0xc3, 0x03, 0x00, 0x0c, 0x3f, 0xf0, 0x0f,
        0xc0, 0x30, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x03,
        0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0c,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x30, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x3f, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00
    }
};

/* File: gpio_extra.c
 * ------------------
 * Support for GPIO event detection and internal pull-up/down
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last modified: Jan 2018
 */

#include "gpio.h"
#include "gpio_extra.h"
#include "_gpio_private.h"
#include <stddef.h>

/*
*  See BCM p 90 for layout of gpio peripheral registers

    Reminder of names/order

    uint32_t eds[2];    // event detect status
    uint32_t ren[2];    // rising edge detect enable
    uint32_t fen[2];    // falling edge detect enable
    uint32_t hen[2];    // high detect enable
    uint32_t len[2];    // low detect enable
    uint32_t aren[2];   // async rising edge detect enable
    uint32_t afen[2];   // async falling edge detect enable

    uint32_t pud;       // pull-up/down signal
    uint32_t pudclk[2]; // pull-up/down clock
*/

/*
Reminder from .h, this is the order the registers need to be placed in register array
enum gpio_event {
    GPIO_DETECT_RISING_EDGE = 0,
    GPIO_DETECT_FALLING_EDGE,
    GPIO_DETECT_HIGH_LEVEL,
    GPIO_DETECT_LOW_LEVEL,
    GPIO_DETECT_ASYNC_RISING_EDGE,
    GPIO_DETECT_ASYNC_FALLING_EDGE,
};
*/

static volatile uint32_t *gpio_reg_for_event(unsigned int event) {
    volatile uint32_t *registers[] = { _gpio->ren, _gpio->fen, _gpio->hen, _gpio->len, _gpio->aren, _gpio->afen};

    if (event < 0 || event >= sizeof(registers) / sizeof(*registers)) {
        return NULL;
    }
    return registers[event];
}

static void gpio_set_detection(unsigned int pin, unsigned int event, unsigned int enabled) {
    volatile uint32_t *reg = gpio_reg_for_event(event);

    if (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST || reg == NULL) {
        return;
    }

    unsigned int bank = pin / 32;
    unsigned int shift = pin % 32;
    if (enabled) {
        reg[bank] |= 1 << shift;
    } else {
        reg[bank] &= ~(1 << shift);
    }
    gpio_clear_event(pin);
}

bool gpio_get_event_detection(unsigned int pin, unsigned int event) {
    volatile uint32_t *reg = gpio_reg_for_event(event);

    if (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST || reg == NULL) {
        return false;
    }

    unsigned int bank = pin / 32;
    unsigned int shift = pin % 32;
    return (reg[bank] & (1 << shift)) != 0;
}

void gpio_disable_event_detection(unsigned int pin, unsigned int event) {
    gpio_set_detection(pin, event, 0);
}

void gpio_enable_event_detection(unsigned int pin, unsigned int event) {
    gpio_set_detection(pin, event, 1);
}

bool gpio_check_event(unsigned int pin) {
    if (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST) {
        return false;
    }

    unsigned int bank = pin / 32;
    unsigned int shift = pin % 32;
    return (_gpio->eds[bank] & (1 << shift)) != 0;
}

void gpio_clear_event(unsigned int pin) {
    if (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST) {
        return;
    }

    unsigned int bank = pin / 32;
    unsigned int shift = pin % 32;
    if (gpio_check_event(pin)) {
        _gpio->eds[bank] = 1 << shift;
    }
}

bool gpio_check_and_clear_event(unsigned int pin) {
    if (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST) {
        return false;
    }

    bool event = gpio_check_event(pin);
    if (event) {
        gpio_clear_event(pin);
    }
    return event;
}

void gpio_disable_all_event_detection(unsigned int pin) {
    if (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST) {
        return;
    }
    for (int i = GPIO_DETECT_RISING_EDGE; i <= GPIO_DETECT_ASYNC_FALLING_EDGE; i++) {
        gpio_set_detection(pin, i, 0);
    }
    gpio_clear_event(pin);
}

/*
 * From Broadcom manual about how to use the pull-up/down:
 * -------------------------------------------------------
 * The GPIO Pull-up/down Clock Registers control the actuation of internal
 * pull-downs on the respective GPIO pins. These registers must be used
 * in conjunction with the GPPUD register to effect GPIO Pull-up/down changes.
 * The following sequence of events is required:
 * 1. Write to GPPUD to set the required control signal
 *    (i.e. Pull-up or Pull-Down or neither to remove the current Pull-up/down)
 * 2. Wait 150 cycles – this provides the required set-up time for the control signal
 * 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish
 *    to modify – NOTE only the pads which receive a clock will be modified,
 *    all others will retain their previous state.
 * 4. Wait 150 cycles – this provides the required hold time for the control signal
 * 5. Write to GPPUD to remove the control signal
 * 6. Write to GPPUDCLK0/1 to remove the clock
 */

enum { GPIO_PUD_DISABLE = 0, GPIO_PUD_PULLDOWN = 1, GPIO_PUD_PULLUP = 2 };

static void gpio_set_pud(unsigned int pin, unsigned int pud) {
    if (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST) {
        return;
    }

    unsigned int bank = pin / 32;
    unsigned int shift = pin % 32;

    _gpio->pud = pud;
    for (volatile int i = 0; i < 150; i++) ;

    _gpio->pudclk[bank] = 1 << shift;
    for (volatile int i = 0; i < 150; i++) ;

    _gpio->pudclk[bank] = 0;
}

void gpio_set_pullup(unsigned int pin) {
    gpio_set_pud(pin, GPIO_PUD_PULLUP);
}

void gpio_set_pulldown(unsigned int pin) {
    gpio_set_pud(pin, GPIO_PUD_PULLDOWN);
}

void gpio_set_pullnone(unsigned int pin) {
    gpio_set_pud(pin, GPIO_PUD_DISABLE);
}

/* File: gpio_interrupts.c
 * -----------------------
 * Dispatcher for GPIO interrupts.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 *         Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last modified: Feb 2022
 */

#include "assert.h"
#include "bits.h"
#include "gpio_interrupts.h"
#include "gpio.h"
#include "gpio_extra.h"
#include "_gpio_private.h"
#include "interrupts.h"
#include <stddef.h>
#include <stdbool.h>

static bool gpio_interrupts_initialized = false;

// This array stores the handlers for gpio interrupts, one per pin.
// If no handler is registered for a given pin, fn at that index is NULL
// global array in bss, values zero'ed at program start
static struct {
    handler_fn_t fn;
    void *aux_data;
} handlers[GPIO_PIN_LAST + 1];

static void gpio_interrupt_dispatch(unsigned int, void *);

void gpio_interrupts_init(void) {
    // okay to re-init this module
    // will not wipe per-pin handlers that were previously registered
    // re-register gpio dispatch as handler with top-level interrupts modules
    // reset gpio interrupt source to disabled state
    interrupts_disable_source(INTERRUPTS_GPIO3);
    interrupts_register_handler(INTERRUPTS_GPIO3, gpio_interrupt_dispatch, NULL);
    gpio_interrupts_initialized = true;
}

void gpio_interrupts_enable(void) {
    assert(gpio_interrupts_initialized);
    interrupts_enable_source(INTERRUPTS_GPIO3);
}

void gpio_interrupts_disable(void) {
    assert(gpio_interrupts_initialized);
    interrupts_disable_source(INTERRUPTS_GPIO3);
}

void gpio_interrupts_register_handler(unsigned int pin, handler_fn_t fn, void *aux_data) {
    assert(gpio_interrupts_initialized);
    assert(pin <= GPIO_PIN_LAST);
    handlers[pin].fn = fn;
    handlers[pin].aux_data = aux_data;
}

static unsigned int get_next_pin(void) {
    unsigned int bank0_zeroes = count_leading_zeroes(_gpio->eds[0]);
    unsigned int bank1_zeroes = count_leading_zeroes(_gpio->eds[1]);
    if (bank0_zeroes != 32) {
        return 31 - bank0_zeroes;
    } else if (bank1_zeroes != 32) {
        return 63 - bank1_zeroes;
    } else {
        return GPIO_PIN_LAST + 1;
    }
}

// gpio_interrupt_dispatch is registered with top-level interrupts
// module as handler for source INTERRUPTS_GPIO3. This handler is
// thus called for all GPIO interrupts and then performs second-level
// dispatch to the per-pin handlers that have been registered with
// this module (gpio_interrupts)
static void gpio_interrupt_dispatch(unsigned int pc, void *unused) {
    unsigned int pin = get_next_pin();
    if (pin <= GPIO_PIN_LAST && handlers[pin].fn != NULL) {
        handlers[pin].fn(pc, handlers[pin].aux_data);
    }
}

/*
 * Module to configure/enable/dispatch interrupts at top-level
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 *         Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last modified: Feb 2022
 */
#include "assert.h"
#include "bits.h"
#include "interrupts.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

// http://xinu.mscs.mu.edu/BCM2835_Interrupt_Controller
// BCM: p196
// This struct is declared to match memory layout of the interrupt registers
struct interrupt_t {
    uint32_t pending_basic;
    uint32_t pending[2];
    uint32_t fiq_control;
    uint32_t enable[2];
    uint32_t enable_basic;
    uint32_t disable[2];
    uint32_t disable_basic;
};

#define INTERRUPT_CONTROLLER_BASE (void *)0x2000B200

static volatile struct interrupt_t * const interrupt = INTERRUPT_CONTROLLER_BASE;
static const uint64_t irq_safe_mask = (1ULL << INTERRUPTS_AUX)       |
        (1ULL << INTERRUPTS_I2CSPISLV) |
        (1ULL << INTERRUPTS_PWA0)      |
        (1ULL << INTERRUPTS_PWA1)      |
        (1ULL << INTERRUPTS_CPR)       |
        (1ULL << INTERRUPTS_SMI)       |
        (1ULL << INTERRUPTS_GPIO0)     |
        (1ULL << INTERRUPTS_GPIO1)     |
        (1ULL << INTERRUPTS_GPIO2)     |
        (1ULL << INTERRUPTS_GPIO3)     |
        (1ULL << INTERRUPTS_VC_I2C)    |
        (1ULL << INTERRUPTS_VC_SPI)    |
        (1ULL << INTERRUPTS_VC_I2SPCM) |
        (1ULL << INTERRUPTS_VC_UART);

extern uint32_t _vectors, _vectors_end;
extern uint32_t *_RPI_INTERRUPT_VECTOR_BASE;

// This array stores the handlers for peripheral interrupts (IRQs) and as well
// as basic interrupts. The 2835 has 64 IRQs, these are entries 0-63. We
// place the basic interrupts after them (see the enumeration in
// interrupts.h). If no handler is registered for a given interrupt source,
// the fn at that index is NULL.
static struct {
    handler_fn_t fn;
    void *aux_data;
} handlers[INTERRUPTS_COUNT];

static bool interrupts_initialized = false;

void interrupts_init(void) {
    // init should happen once and only once
    // A re-init would disable all previously enabled sources
    // raise error rather than do that.
    assert(!interrupts_initialized);

    // disable interrupt generation system-wide
    interrupts_global_disable();
    // disable all sources
    interrupt->disable_basic = 0xffffffff;
    interrupt->disable[0] = 0xffffffff;
    interrupt->disable[1] = 0xffffffff;

    // copy table of vectors to destination RPI_INTERRUPT_VECTOR_BASE
    // _vector and _vector_end are symbols defined in interrupt_asm.s
    // that mark start/end of table to be copied
    uint32_t *dst = _RPI_INTERRUPT_VECTOR_BASE;
    uint32_t *src = &_vectors;
    uint32_t n = &_vectors_end - &_vectors;
    for (int i = 0; i < n; i++) {
        dst[i] = src[i];
    }
    interrupts_initialized = true;
}

// verify vector table correctly installed, i.e. interrupts_init() was
// called and IRQ table entry is not corrupted
static bool vector_table_is_installed(void) {
    const int IRQ_INDEX = 6;
    return _RPI_INTERRUPT_VECTOR_BASE[IRQ_INDEX] == (&_vectors)[IRQ_INDEX];
}

// basic IRQ sources are ARM-specific
static bool is_basic(unsigned int irq_source) {
    return irq_source >= INTERRUPTS_BASIC_BASE && irq_source < INTERRUPTS_BASIC_END;
}

// these IRQ sources are shared between CPU and GPU
static bool is_shared(unsigned int irq_source) {
    return irq_source >= INTERRUPTS_SHARED_START && irq_source < INTERRUPTS_SHARED_END;
}

// Returns whether a given IRQ is safe to be used.
// From the BCM2835 manual 7.5: "the table above has many empty entries.
// These should not be enabled as they will interfere with the GPU operation."
// Returns whether the irq is a non-empty entry, and thus safe to be enabled.
static bool is_safe(unsigned int irq_source) {
    uint64_t bit = 1ULL << irq_source;
    return ((bit & irq_safe_mask) != 0);
}

static bool is_valid(unsigned int irq_source) {
    return is_basic(irq_source) || (is_shared(irq_source) && is_safe(irq_source));
}

void interrupts_enable_source(unsigned int source) {
    assert(interrupts_initialized);
    assert(is_valid(source));

    if (is_basic(source)) {
        unsigned int shift = source - INTERRUPTS_BASIC_BASE;
        interrupt->enable_basic |= 1 << shift;
    } else if (is_shared(source)) {
        unsigned int bank = source / 32;
        unsigned int shift = source % 32;
        interrupt->enable[bank] |= 1 << shift;
    }
}

void interrupts_disable_source(unsigned int source) {
    assert(interrupts_initialized);
    assert(is_valid(source));

    if (is_basic(source)) {
        unsigned int shift = source - INTERRUPTS_BASIC_BASE;
        interrupt->disable_basic |= 1 << shift;
    } else if (is_shared(source)) {
        unsigned int bank = source / 32;
        unsigned int shift = source % 32;
        interrupt->disable[bank] |= 1 << shift;
     }
}

void interrupts_register_handler(unsigned int source, handler_fn_t fn, void *aux_data) {
    assert(interrupts_initialized);
    assert(vector_table_is_installed());
    assert(is_valid(source));

    handlers[source].fn = fn;
    handlers[source].aux_data = aux_data;
}

static int get_next_source(void) {
    unsigned int basic_zeroes = count_leading_zeroes(interrupt->pending_basic);
    unsigned int pending0_zeroes = count_leading_zeroes(interrupt->pending[0]);
    unsigned int pending1_zeroes = count_leading_zeroes(interrupt->pending[1]);
    // We only care about basic bits 0-7:
    //  - bits 8 and 9 are for the pending registers, which we always check
    //  - higher bits are GPU which we ignore
    if (basic_zeroes >= 24) {
        // If bit 0 is set there will be 31 leading zeroes, while if bit 31 is set
        // there are 0 leading zeroes. So the number is 31 - number of zeroes; add
        // INTERRUPTS_BASIC_BASE for index into table.
        return (31 - basic_zeroes) + INTERRUPTS_BASIC_BASE;
    } else if (pending0_zeroes != 32) {
        return (31 - pending0_zeroes);
    } else if (pending1_zeroes != 32) {
        return (63 - pending1_zeroes);
    } else {
        return INTERRUPTS_NONE;
    }
}

// The dispatch function must be extern as it is called from another module
// (interrupts_asm.s). However, it not otherwise intended as a public
// function and is not declared or documented in the interface.
void interrupt_dispatch(unsigned int pc);

void interrupt_dispatch(unsigned int pc) {
    int source = get_next_source();
    if (source < INTERRUPTS_COUNT && handlers[source].fn != NULL) {
        handlers[source].fn(pc, handlers[source].aux_data);
    }
}


/*
 *  Assembly code for interrupt vector table and functions
 *  to enable/disable IRQ interrupts on the Rapsberry Pi in CS107E.
 *
 *  Author: Philip Levis <pal@cs.stanford.edu>
 *          Julie Zelenski <zelenski@cs.stanford.edu>
 *
 *  Last update: 2/20/20
 *
 *  Enable/disable interrupts.
 *
 *  CPSR = current program status register
 *        lower 8 bits are:
 *           7 6 5 4 3 2 1 0
 *          +-+-+-+---------+
 *          |I|F|T|   Mode  |
 *          +-+-+-+---------+
 *
 *    I     : = 0 IRQ enabled, = 1 IRQ disabled
 *    F     : = 0 FIQ enabled, = 1 FIQ disabled
 *    T     : = 0 indicates ARM execution, = 1 is thumb execution
 *    Mode  : current mode
 */

.global interrupts_global_enable
interrupts_global_enable:
    mrs r0, cpsr        // copy cpsr value to regular register
    bic r0, r0, #0x80   // clear I=0 enables IRQ interrupts
    msr cpsr_c, r0      // copy back, control bits only
    bx lr

.global interrupts_global_disable
interrupts_global_disable:
    mrs r0, cpsr        // copy cpsr value to regular register
    orr r0, r0, #0x80   // set I=1 disables IRQ interrupts
    msr cpsr_c, r0      // copy back, control bits only
    bx lr

// destination address for vector table (0)
.global _RPI_INTERRUPT_VECTOR_BASE
    _RPI_INTERRUPT_VECTOR_BASE:     .word   0

.global _vectors
.global _vectors_end

// Vector table has one instruction for each of the eight exceptions
// Bounces to absolute destination address accessed via pc-relative label
_vectors:
    ldr pc, abort_addr
    ldr pc, abort_addr
    ldr pc, abort_addr
    ldr pc, abort_addr
    ldr pc, abort_addr
    ldr pc, abort_addr
    ldr pc, interrupt_addr
    ldr pc, abort_addr
    
    abort_addr:                   .word abort_asm
    interrupt_addr:               .word interrupt_asm

_vectors_end:

// Used for fatal exceptions
abort_asm:
    mov   sp, #0x4000               // init stack
    bl    pi_abort                  // pi_abort does not return

// Used for general interrupts
interrupt_asm:
    mov   sp, #0x8000               // init stack for interrupt mode
    sub   lr, lr, #4                // compute resume addr from old pc
    push  {r0-r12, lr}              // save all registers (overkill, but simple & correct)
    mov   r0, lr                    // pass resume addr as argument to dispatch
    bl    interrupt_dispatch        // call C function
    ldm   sp!, {r0-r12, pc}^        // leave interrupt mode
                                    // restore saved regs, pc restored to lr (resume addr)
                                    // The ^ changes to previous mode, restores cpsr

/*
 * Interface to Raspberry Pi mailbox system, used by libpi to interact
 * with GPU. Note that this interface has been deprecated and so future
 * code should use the property interface instead.
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 *         Philip Levis <pal@cs.stanford.edu>
 * Date: 6/20/17
 */

#include "mailbox.h"

#define MAILBOX_BASE     0x2000B880

// This bit is set in status register if no space to write to mailbox
#define MAILBOX_FULL   (1<<31)

// This bit is set in status register if nothing to read in mailbox
#define MAILBOX_EMPTY  (1<<30)

// This prevents the GPU and CPU from caching mailbox messages
#define GPU_NOCACHE 0x40000000

typedef struct {
    unsigned int read;
    unsigned int padding[3]; // note padding to skip 3 words
    unsigned int peek;
    unsigned int sender;
    unsigned int status;
    unsigned int configuration;
    unsigned int write;
} mailbox_t;


// mailbox is volatile because the GPU can also write to it
static volatile mailbox_t *mailbox = (volatile mailbox_t *)MAILBOX_BASE;


bool mailbox_request(unsigned int channel, unsigned int addr) {
    if (!mailbox_write(channel, addr))
        return false;
    return (mailbox_read(channel) == 0); // returned data is 0 on success
}

bool mailbox_write(unsigned int channel, unsigned int addr) {
    // mailbox has a maximum of 16 channels
    if (channel >= MAILBOX_MAXCHANNEL) {
        return false;
    }

    // addr must be a multiple of 16
    if (addr & 0xF) {
        return false;
    }

    // wait until mailbox is not full ...
    while (mailbox->status & MAILBOX_FULL) ;

    // set GPU_NOCACHE bit so that the GPU does not cache the memory
    addr |= GPU_NOCACHE;

    // addr is a multiple of 16, so the low 4 bits are zeros
    // 4-bit channel number is stuffed into those low bits
    mailbox->write = addr | channel;
    return true;
}

unsigned int mailbox_read(unsigned int channel) {
    if (channel >= MAILBOX_MAXCHANNEL) {
        return 1;
    }

    while (1) {
        // wait until mailbox is not empty ...
        while (mailbox->status & MAILBOX_EMPTY) ;
        // read the data, low 4 bits are channel, upper 28 are result
        unsigned int data = mailbox->read;
        if ((data & 0xF) == channel) { // if this message is for our channel
            return (data >> 4);
        }
    }
    return 1;
}

/* File: pi.c
 * ----------
 * Utility functions for Raspberry Pi.
 * (reboot/abort execution, control on-board LEDs)
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 *         Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last modified: Jan 2018
 */

#include "pi.h"
#include <stdint.h>
#include "timer.h"
#include "uart.h"

void pi_reboot(void) {
    static const int PM_RSTC = 0x2010001c;
    static const int PM_WDOG = 0x20100024;
    static const int PM_PASSWORD = 0x5a000000;
    static const int PM_RSTC_WRCFG_FULL_RESET = 0x00000020;

    volatile uint32_t * reg_pm_wdog = (uint32_t *)PM_WDOG;
    volatile uint32_t * reg_pm_rstc = (uint32_t *)PM_RSTC;

    uart_putchar(EOT);
    // give output time to flush.
    for (int i = 0; i < 100000; i++) {
        __asm__("nop");
    }

    // timeout = 1/16th of a second? (whatever)
    *reg_pm_wdog = PM_PASSWORD | 1;
    *reg_pm_rstc = PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
    while (1)
        ;
}

void pi_abort(void) {
    gpio_set_output(PI_PWR_LED);
    while (1) {  // Infinite loop, flash the red PWR LED
        pi_led_toggle(PI_PWR_LED);
        timer_delay_ms(200);
    }
}

void pi_led_on(int led) {
    if (led != PI_ACT_LED && led != PI_PWR_LED) {
        return;
    }
    gpio_set_output(led);
    gpio_write(led, 1);
}

void pi_led_off(int led) {
    if (led != PI_ACT_LED && led != PI_PWR_LED) {
        return;
    }
    gpio_set_output(led);
    gpio_write(led, 0);
}

void pi_led_toggle(int led) {
    if (led != PI_ACT_LED && led != PI_PWR_LED) {
        return;
    }
    gpio_set_output(led);
    gpio_write(led, !gpio_read(led));
}

/*
 * Lookup table to access key information for a PS/2 scan code.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 */

#include "ps2_keys.h"

#define UNUSED { PS2_KEY_NONE, PS2_KEY_NONE }

// For completeness, array lists all keys on the full PS/2 keyboard.
// Refer to the assign5 writeup for spec on which keys are required
// to be implemented by your keyboard driver.

ps2_key_t const ps2_keys[] = {
    /* scan code */
    /* 00 */      UNUSED,
    /* 01 */   { PS2_KEY_F9, PS2_KEY_F9 },
    /* 02 */      UNUSED,
    /* 03 */   { PS2_KEY_F5, PS2_KEY_F5 },
    /* 04 */   { PS2_KEY_F3, PS2_KEY_F3 },
    /* 05 */   { PS2_KEY_F1, PS2_KEY_F1 },
    /* 06 */   { PS2_KEY_F2, PS2_KEY_F2 },
    /* 07 */   { PS2_KEY_F12, PS2_KEY_F12 },
    /* 08 */      UNUSED,
    /* 09 */   { PS2_KEY_F10, PS2_KEY_F10 },
    /* 0A */   { PS2_KEY_F8,  PS2_KEY_F8 },
    /* 0B */   { PS2_KEY_F6,  PS2_KEY_F6 },
    /* 0C */   { PS2_KEY_F4,  PS2_KEY_F4 },
    /* 0D */   { '\t', '\t' },
    /* 0E */   { '`', '~' },
    /* 0F */      UNUSED,
    /* 10 */      UNUSED,
    /* 11 */   { PS2_KEY_ALT, PS2_KEY_ALT },
    /* 12 */   { PS2_KEY_SHIFT, PS2_KEY_SHIFT },
    /* 13 */      UNUSED,
    /* 14 */   { PS2_KEY_CTRL, PS2_KEY_CTRL },
    /* 15 */   { 'q', 'Q' },
    /* 16 */   { '1', '!' },
    /* 17 */      UNUSED,
    /* 18 */      UNUSED,
    /* 19 */      UNUSED,
    /* 1A */   { 'z', 'Z' },
    /* 1B */   { 's', 'S' },
    /* 1C */   { 'a', 'A' },
    /* 1D */   { 'w', 'W' },
    /* 1E */   { '2', '@' },
    /* 1F */      UNUSED,
    /* 20 */      UNUSED,
    /* 21 */   { 'c', 'C' },
    /* 22 */   { 'x', 'X' },
    /* 23 */   { 'd', 'D' },
    /* 24 */   { 'e', 'E' },
    /* 25 */   { '4', '$' },
    /* 26 */   { '3', '#' },
    /* 27 */      UNUSED,
    /* 28 */      UNUSED,
    /* 29 */   { ' ', ' ' },
    /* 2A */   { 'v', 'V' },
    /* 2B */   { 'f', 'F' },
    /* 2C */   { 't', 'T' },
    /* 2D */   { 'r', 'R' },
    /* 2E */   { '5', '%' },
    /* 2F */      UNUSED,
    /* 30 */      UNUSED,
    /* 31 */   { 'n', 'N' },
    /* 32 */   { 'b', 'B' },
    /* 33 */   { 'h', 'H' },
    /* 34 */   { 'g', 'G' },
    /* 35 */   { 'y', 'Y' },
    /* 36 */   { '6', '^' },
    /* 37 */      UNUSED,
    /* 38 */      UNUSED,
    /* 39 */      UNUSED,
    /* 3A */   { 'm', 'M' },
    /* 3B */   { 'j', 'J' },
    /* 3C */   { 'u', 'U' },
    /* 3D */   { '7', '&' },
    /* 3E */   { '8', '*' },
    /* 3F */      UNUSED,
    /* 40 */      UNUSED,
    /* 41 */   { ',', '<' },
    /* 42 */   { 'k', 'K' },
    /* 43 */   { 'i', 'I' },
    /* 44 */   { 'o', 'O' },
    /* 45 */   { '0', ')' },
    /* 46 */   { '9', '(' },
    /* 47 */      UNUSED,
    /* 48 */      UNUSED,
    /* 49 */   { '.', '>' },
    /* 4A */   { '/', '?' },
    /* 4B */   { 'l', 'L' },
    /* 4C */   { ';', ':' },
    /* 4D */   { 'p', 'P' },
    /* 4E */   { '-', '_' },
    /* 4F */      UNUSED,
    /* 50 */      UNUSED,
    /* 51 */      UNUSED,
    /* 52 */   { '\'', '"' },
    /* 53 */      UNUSED,
    /* 54 */   { '[', '{' },
    /* 55 */   { '=', '+' },
    /* 56 */      UNUSED,
    /* 57 */      UNUSED,
    /* 58 */   { PS2_KEY_CAPS_LOCK, PS2_KEY_CAPS_LOCK },
    /* 59 */   { PS2_KEY_SHIFT, PS2_KEY_SHIFT },
    /* 5A */   { '\n', '\n' },
    /* 5B */   { ']', '}' },
    /* 5C */      UNUSED,
    /* 5D */   { '\\', '|' },
    /* 5E */      UNUSED,
    /* 5F */      UNUSED,
    /* 60 */      UNUSED,
    /* 61 */      UNUSED,
    /* 62 */      UNUSED,
    /* 63 */      UNUSED,
    /* 64 */      UNUSED,
    /* 65 */      UNUSED,
    /* 66 */   { '\b', '\b' },  // delete key produces backspace (= ascii 0x08 = \b)
    /* 67 */      UNUSED,
    /* 68 */      UNUSED,
    /* 69 */   { PS2_KEY_END, '1' },
    /* 6A */      UNUSED,
    /* 6B */   { PS2_KEY_ARROW_LEFT, '4' },
    /* 6C */   { PS2_KEY_HOME, '7' },
    /* 6D */      UNUSED,
    /* 6E */      UNUSED,
    /* 6F */      UNUSED,
    /* 70 */   { PS2_KEY_INSERT, '0' },
    /* 71 */   { PS2_KEY_DELETE, '.' },
    /* 72 */   { PS2_KEY_ARROW_DOWN, '2' },
    /* 73 */   { '5', '5' },
    /* 74 */   { PS2_KEY_ARROW_RIGHT, '6' },
    /* 75 */   { PS2_KEY_ARROW_UP, '8' },
    /* 76 */   { PS2_KEY_ESC, PS2_KEY_ESC },
    /* 77 */   { PS2_KEY_NUM_LOCK, PS2_KEY_NUM_LOCK },
    /* 78 */   { PS2_KEY_F11, PS2_KEY_F11 },
    /* 79 */   { '+', '+' },
    /* 7A */   { PS2_KEY_PAGE_DOWN, '3' },
    /* 7B */   { '-', '-' },
    /* 7C */   { '*', '*' },
    /* 7D */   { PS2_KEY_PAGE_UP, '9' },
    /* 7E */   { PS2_KEY_SCROLL_LOCK, 0 },
    /* 7F */      UNUSED,
    /* 80 */      UNUSED,
    /* 81 */      UNUSED,
    /* 82 */      UNUSED,
    /* 83 */   { PS2_KEY_F7, PS2_KEY_F7 },
};

/* File: ringbuffer.c
 * ------------------
 * Simple lock-free ring buffer that allows for concurrent
 * access by 1 reader and 1 writer.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 *         Julie Zelenski <zelenski@cs.stanford.edu>
 */

#include "ringbuffer.h"
#include "assert.h"
#include "malloc.h"

#define LENGTH 512

/*
 * A ring buffer is represented using a struct containing a fixed-size array
 * and head and tail fields, which are indexes into the entries[] array.
 * head is the index of the frontmost element (head advances during dequeue)
 * tail is the index of the next position to use (tail advances during enqueue)
 * Both head and tail advance circularly, i.e. index = (index + 1) % LENGTH
 * The ring buffer is empty if tail == head
 * The ring buffer is full if tail + 1 == head
 * (Note: one slot remains permanently empty to distinguish full from empty)
 */

struct ringbuffer {
    int entries[LENGTH];
    unsigned int head, tail;
};


rb_t *rb_new(void) {
    rb_t *rb = malloc(sizeof(struct ringbuffer));
    rb->head = rb->tail = 0;
    return rb;
}

bool rb_empty(rb_t *rb) {
    assert(rb != NULL);
    return rb->head == rb->tail;
}

bool rb_full(rb_t *rb) {
    assert(rb != NULL);
    return (rb->tail + 1) % LENGTH == rb->head;
}

/*
 * Note: enqueue is called by writer. enqueue advances rb->tail,
 * no changes to rb->head.  This design allows safe concurrent access.
 */
bool rb_enqueue(rb_t *rb, int elem) {
    assert(rb != NULL);
    if (rb_full(rb)) {
        return false;
    }

    rb->entries[rb->tail] = elem;
    rb->tail = (rb->tail + 1) % LENGTH;
    return true;
}

/*
 * Note: dequeue is called by reader. dequeue advances rb->head,
 * no changes to rb->tail. This design allows safe concurrent access.
 */
bool rb_dequeue(rb_t *rb, int *p_elem) {
    assert(rb != NULL && p_elem != NULL);
    if (rb_empty(rb)) {
        return false;
    }

    *p_elem = rb->entries[rb->head];
    rb->head = (rb->head + 1) % LENGTH;
    return true;
}

/*
 * Hardware abstractions for a serial port (UART).
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 * Date: Jan 24, 2016
 */

#include "gpio.h"
#include <stdint.h>
#include "uart.h"

struct UART {
    uint32_t data; // I/O Data
    uint32_t ier;  // Interrupt enable
    uint32_t iir;  // Interrupt identify and fifo enables/clears
    uint32_t lcr;  // line control register
    uint32_t mcr;  // modem control register
    uint32_t lsr;  // line status register
    uint32_t msr;  // modem status register
    uint32_t scratch;
    uint32_t cntl; // control register
    uint32_t stat; // status register
    uint32_t baud; // baud rate register
} ;

// AUX bits
#define AUX_ENABLES 0x20215004
#define AUX_ENABLE  0x00000001

// Mini UART
#define MINI_UART_BASE 0x20215040

#define MINI_UART_IIR_RX_FIFO_CLEAR  0x00000002
#define MINI_UART_IIR_TX_FIFO_CLEAR  0x00000004
#define MINI_UART_IIR_RX_FIFO_ENABLE 0x00000080
#define MINI_UART_IIR_TX_FIFO_ENABLE 0x00000040

#define MINI_UART_LCR_8BIT       0x00000003

#define MINI_UART_LSR_RX_READY   0x00000001
#define MINI_UART_LSR_TX_READY   0x00000010
#define MINI_UART_LSR_TX_EMPTY   0x00000020

#define MINI_UART_CNTL_TX_ENABLE 0x00000002
#define MINI_UART_CNTL_RX_ENABLE 0x00000001

static volatile struct UART *uart = (struct UART*) MINI_UART_BASE;
static bool initialized = false;


/* Key detail from the Broadcom Peripherals data sheet p.10
 *
 * GPIO pins should be set up first the before enabling the UART.
 * The UART core is build to emulate 16550 behaviour.
 * So when it is enabled any data at the inputs will immediately be received .
 * If the UART1_RX line is low (because the GPIO pins have not been set-up yet)
 * that will be seen as a start bit and the UART will start receiving 0x00-characters.
 * [...] The result will be that the FIFO is full and overflowing in no time flat.
 */

void uart_init(void) {
    gpio_set_function(GPIO_TX, GPIO_FUNC_ALT5);
    gpio_set_function(GPIO_RX, GPIO_FUNC_ALT5);

    int *aux = (int*)AUX_ENABLES;
    *aux |= AUX_ENABLE; // must enable mini-uart before accessing registers

    uart->ier  = 0;
    uart->cntl = 0;
    uart->lcr  = MINI_UART_LCR_8BIT;
    uart->mcr  = 0;
    uart->ier  = 0;
    uart->iir  = MINI_UART_IIR_RX_FIFO_CLEAR |
                 MINI_UART_IIR_RX_FIFO_ENABLE |
                 MINI_UART_IIR_TX_FIFO_CLEAR |
                 MINI_UART_IIR_TX_FIFO_ENABLE;

    uart->baud = 270; // baud rate ((250,000,000/115200)/8)-1 = 270

    uart->cntl = MINI_UART_CNTL_TX_ENABLE | MINI_UART_CNTL_RX_ENABLE;
    initialized = true;
}

unsigned char uart_recv(void) {
    while (!uart_haschar()) ; // wait for char to arrive
    return uart->data & 0xFF;
}

void uart_send(unsigned char byte) {
    while (!(uart->lsr & MINI_UART_LSR_TX_EMPTY)) ;
    uart->data = byte & 0xFF;
}

void uart_flush(void) {
    while (!(uart->lsr & MINI_UART_LSR_TX_EMPTY)) ;
}

bool uart_haschar(void) {
    return (uart->lsr & MINI_UART_LSR_RX_READY);
}

// RE: line endings
// canonial use is '\n' newline as sole line terminator (both read/write)
// but connected terminal may expect to receive a CR-LF sequence from Pi
// and may send a CR to Pi for return/enter key. uart_getchar and uart_putchar
// internally convert chars, client can simply send/receive newline
// Use uart_send/uart_recv to send/receive raw byte, no conversion

int uart_getchar(void) {
    int ch = uart_recv();
    if (ch == EOT) {
        return EOF;    // convert EOT to EOF
    }
    if (ch == '\r') {
        return '\n';    // convert CR to newline
    }
    return ch;
}

int uart_putchar(int ch) {
    // force initialize if not yet done
    // this fallback is special case for uart_putchar as
    // without it, all output (print/assert) can fail and no
    // clear indication because of self-referential nature of problem
    if (!initialized) uart_init();

    // convert newline to CR LF sequence by inserting CR
    if (ch == '\n') {
        uart_send('\r');
    }
    uart_send(ch);
    return ch;
}

int uart_putstring(const char *str) {
    int n = 0;
    while (str[n]) {
        uart_putchar(str[n]);
        n++;
    }
    return n;
}