#include <stdio.h>
#include "ibm.h"
#include "io.h"
#include "nvr.h"
#include "nvr_tc8521.h"
#include "rtc_tc8521.h"
#include "pic.h"
#include "timer.h"
#include "rtc.h"
#include "paths.h"
#include "config.h"
#include "nmi.h"

static pc_timer_t nvr_onesec_timer;
static int nvr_onesec_cnt = 0;

static void tc8521_onesec(void *p) {
        nvr_onesec_cnt++;
        if (nvr_onesec_cnt >= 100) {
                tc8521_tick();
                nvr_onesec_cnt = 0;
        }
        timer_advance_u64(&nvr_onesec_timer, 10000 * TIMER_USEC);
}

void write_tc8521(uint16_t addr, uint8_t val, void *priv) {
        uint8_t page = nvrram[0x0D] & 3;

        addr &= 0x0F;
        if (addr < 0x0D)
                addr += 16 * page;

        if (addr >= 0x10 && nvrram[addr] != val)
                nvr_dosave = 1;

        nvrram[addr] = val;
}

uint8_t read_tc8521(uint16_t addr, void *priv) {
        uint8_t page = nvrram[0x0D] & 3;

        addr &= 0x0F;
        if (addr < 0x0D)
                addr += 16 * page;

        return nvrram[addr];
}

void tc8521_loadnvr() {
        FILE *f;

        nvrmask = 63;
        oldromset = romset;
        switch (romset) {
        case ROM_T1000:
                f = nvrfopen("t1000.nvr", "rb");
                break;
        case ROM_T1200:
                f = nvrfopen("t1200.nvr", "rb");
                break;
        default:
                return;
        }
        if (!f) {
                memset(nvrram, 0xFF, 64);
                nvrram[0x0E] = 0; /* Test register */
                if (!enable_sync) {
                        memset(nvrram, 0, 16);
                }
                return;
        }
        fread(nvrram, 64, 1, f);
        if (enable_sync)
                tc8521_internal_sync(nvrram);
        else
                tc8521_internal_set_nvrram(nvrram); /* Update the internal clock state based on the NVR registers. */
        fclose(f);
}

void tc8521_savenvr() {
        FILE *f;
        switch (oldromset) {
        case ROM_T1000:
                f = nvrfopen("t1000.nvr", "wb");
                break;
        case ROM_T1200:
                f = nvrfopen("t1200.nvr", "wb");
                break;
        default:
                return;
        }
        fwrite(nvrram, 64, 1, f);
        fclose(f);
}

void nvr_tc8521_init() {
        io_sethandler(0x2C0, 0x10, read_tc8521, NULL, NULL, write_tc8521, NULL, NULL, NULL);
        timer_add(&nvr_onesec_timer, tc8521_onesec, NULL, 1);
}
